embedded systems programming c++ classes. contents introduction user defined data types classes and...

Post on 21-Dec-2015

232 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Embedded Systems Programming

C++ Classes

Contents

• Introduction• User defined data types• Classes and encapsulation• Implementation/interface• Classes and objects• Creating/initializing objects – constructors• Destroying objects – destructors• Other features of classes

Introduction• Classes are the core of C++’s support for object

oriented programming

• They allow the programmer to create abstract data types in a similar way that struct does in C

– However the C++ class also supports encapsulation whereas struct does not

– Encapsulation allows the programmer to hide details about the implementation

• First we will review the struct construct

User defined data types

• C (and C++) allow user defined data types to be created using the struct construct

• For example, we could create a Date data type to represent dates

struct Datestruct Date{{

int d;int d;int m;int m;int y;int y;

};};

• We could create variables (objects) of the Date data type as well as writing functions that operate on these objects

extern void set_date(Date*, int, int, int);extern void set_date(Date*, int, int, int);extern void print_date(const Date*);extern void print_date(const Date*);  void main() void main() {{

Date* date = new Date;Date* date = new Date;set_date(date,28,8,2003)set_date(date,28,8,2003)print_date(date);print_date(date);

}}

• In C++, we can include the functions as part of the struct declaration so they become member functions– This means we don’t have to pass the objects as

arguments into the functions

struct Datestruct Date{{

int d;int d;int m;int m;int y;int y;void set(int,int,int);void set(int,int,int);

void print();void print();};};

• The member functions are defined using the :: operator as follows :

void Date::set(int dd, int mm, int yy)void Date::set(int dd, int mm, int yy){{

d=dd; d=dd; m=mm;m=mm;y=yy;y=yy;

}}  void Date::print()void Date::print(){{

printf(“Day, month, year = %d %d %d ”, d, m, y);printf(“Day, month, year = %d %d %d ”, d, m, y);}}

• Finally Date objects can be created and member functions called as follows :– Note that member functions are called

through the object (variable) name

void main()void main(){{

Date today;Date today;today.set(12,8,2003)today.set(12,8,2003)today.print();today.print();

}}

Classes and encapsulation

• Classes in C++ are similar and have similar syntax and uses as structures in C with one key difference– They support the idea of encapsulation– The implementation of the class is hidden

from the interface to the class– This is achieved through the use of public and

private member access specifiers

• We can define a Date class as follows :

class Date class Date {{

private:private:int d;int d;int m;int m;int y;int y;

public:public:void set(int,int,int);void set(int,int,int);void print();void print();void advance();void advance();

};};

• An additional member function advance() has been added which advances the date by one day

• Apart from that, this has the same functionality as the Date structure

• The key difference is the separation of the class into private and public

• This separation underpins the ideas behind encapsulation (or implementation/interface)

Key point

• Only public member functions of Date can access private members of the class– Enforced by rules of the language– If we try to access a private class member

from outside a public member function, a compilation error is triggered

• Implementation of Date::set() is as follows

• Accesses Date::d, Date::m, Date::y which is OK as it’s a public member function

void Date::set(int dd, int mm, int yy)void Date::set(int dd, int mm, int yy){{

d=dd; d=dd; m=mm;m=mm;y=yy;y=yy;

}}

• The following is illegal code

• This is an attempt to access a private class member from outside a public member function

int get_year(Date date)int get_year(Date date){{

return date.y;return date.y; // Error! // Error! }}

int main()int main(){{

Date today;Date today;today.d=28;today.d=28; // Error!// Error!today.m=8;today.m=8; // Error!// Error!today.y=1998;today.y=1998; // Error!// Error!

}}

• In order to access the private class members Date::d, Date::m, Date::y, we have to provide public member access functions

class Date class Date {{

private:private:int d;int d;int m;int m;int y;int y;

public:public:void set(int,int,int);void set(int,int,int);void print();void print();void advance();void advance();int day() {return d;}int day() {return d;} // access function// access functionint month() {return m; }int month() {return m; } // access function// access functionint year() {return y;}int year() {return y;} // access function// access function

};};

• You may wonder (quite rightly!) whether this is an undue computational overhead

– In order to access a private class member, we have to go through an additional function call

• However, access restriction of the classes private members is key to encapsulation

– Implementation/interface

Implementation/interface

• We can justify the sub-division of a class into private and public by considering the idea of the implementation of the class and the interface to the class

• The implementation of the class is represented by the private class members and public member function bodies (which use the private members)

• The interface to the class is represented by the public member functions headers

Date

private

publicvoid set()void print()void advance()int date()int month()int year()

int dint mint y

Implementation

Interface

Changing the implementation of Date

• Suppose we decide to change the implementation of Date and represent the date internally in the Julien format– This represents the number of days since

1/1/1900 from which the current day, month and year can be computed algorithmically

class Date class Date {{

private:private:long julien;long julien; // Number of days since 1/1/1900// Number of days since 1/1/1900

public:public:void set(int,int,int);void set(int,int,int);void print();void print();void advance();void advance();int day() {return d;}int day() {return d;} // access function// access functionint month() {return m; }int month() {return m; } // access function// access functionint year() {return y;}int year() {return y;} // access function// access function

};};

• The key point is that public member function body implementations need to change to reflect the changed private members

• However, the public member function headers remain the same

• These represent the interface to the Date class as seen by application programs using the class

Date :: day()Date :: day(){{

// complicated algorithm// complicated algorithm}}

Date :: month()Date :: month(){{

// complicated algorithm// complicated algorithm}}

Date :: year()Date :: year(){{

// Simple algorithm (taking into account leap years)// Simple algorithm (taking into account leap years)}}

Date::advance()Date::advance(){{

julien++;julien++;}}

Key point

• Because of encapsulation, applications using the Date class will not change as they only interact with the class through public member function calls

• This leads to more robust extendible systems

• For example, some external function weekend() will still be correct even after the changes to Date

– The function interacts with Date through the public member function day()

int weekend(Date date)int weekend(Date date){{

// Returns // Returns truetrue if the date falls on a weekend if the date falls on a weekendreturn ((date.day()==0)||(date.day()==6));return ((date.day()==0)||(date.day()==6));

}}

Classes and objects

• Its important to be clear about the distinction between classes and objects

• It may seem obvious but it does cause confusion

• Essentially an object is an instantiation of a class– We can create many objects of the same

class

• We can create several date objects as follows :

Date date;date.set(14,4,2003)Date another_date; another_date.set(15,4,2003);

date

another_date

Date

Apr 14, 2003

Date

Apr 15, 2003

• We have 1 class

– Date

• We have 2 objects

– date

– another_date

• Typically class names will start with upper case and object names will start with lower case

Creating/initializing objects – constructors

• Objects can be created and initialized by declaring special public member functions called constructors with the same name as the class

• A nice feature of constructors is that function overloading can be used so that objects can be initialized in different ways

class Date class Date {{

private:private:int d,m,y;int d,m,y;

public:public:Date();Date(); // constructor// constructorDate(int,int,int);Date(int,int,int); // constructor// constructorDate(char *);Date(char *); // constructor// constructorvoid set(int,int,int);void set(int,int,int);void print();void print();void advance();void advance();int day() {return d;}int day() {return d;} // access function// access functionint month() {return m; }int month() {return m; } // access function// access functionint year() {return y;}int year() {return y;} // access function// access function

};};

• The implementation of the constructors are as follows :

Date::Date()Date::Date(){{ // default construcotr// default construcotr}}

Date::Date(int dd, int mm, int yy)Date::Date(int dd, int mm, int yy){{

d=dd; m=mm; y=yy;d=dd; m=mm; y=yy;}}

Date::Date(char* date_string)Date::Date(char* date_string){{

// Parse the string and assign to d, m, y// Parse the string and assign to d, m, y}}

• We can now create and initialize objects as follows :

Date tomorrow;Date tomorrow; // Date() called// Date() called

Date today(1,9,1998);Date today(1,9,1998); // Date(int,int,int) called// Date(int,int,int) called

Date yesterday("31Date yesterday("31stst August 1998"); August 1998"); // Date(char*) called// Date(char*) called

• Note that the constructor is automatically called when an object is declared

– It doesn’t have to be initialized (although it is usually good practice to do so)

– However, the default constructor must be present if we wish to create uninitialized objects

• Note also that we can create objects dynamically and this also involves calling a constructor

Date* today = new Date(1,9,1998);Date* today = new Date(1,9,1998);

today->advance();today->advance();

Destroying objects – destructors

• Destructors are member functions which are called automatically (see later) in order to delete an object and release all of the memory taken by that object– Unlike Java, C++ has no automatic garbage collection

• For a simple class like Date, no dynamic allocation of private member variables has taken place so the compiler can delete Date objects by simply deleting each private member variable

• For classes where private members have been dynamically allocated, we must implement the destructor in order for the object to be completely deleted

class myClassclass myClass{{

private:private:char* message;char* message;int message_length;int message_length;

public:public: myClass(char* m, int len);myClass(char* m, int len); // constructor// constructor~myClass();~myClass(); // destructor// destructor

};};

myClass::myClass(char* m, int len)myClass::myClass(char* m, int len){{

message_length=len;message_length=len;message=new char[len];message=new char[len];strcpy(message,m);strcpy(message,m);

}}

myClass::~myClass()myClass::~myClass(){{

delete[] message;delete[] message;}}

• Destructors are called automatically when :– The delete operator is called for a

dynamically created object– An automatically created object goes out of

scope– The program (main) (or a function)

terminates for a statically created object – The destructors for globally defined objects

are called last of all

Other features of classes

• We will look at a few other features of classes– this self-reference– Friends– Static class members

Self-reference - this

• Each (non-static) member function has a access to a pointer to the instantiated object from which the member function was called (!!)

• So, for example, in our Date class, member functions have access to a (constant) pointer of type Date*

Date

private

public

.

.void advance() { // access to this }.

int dint mint y

• The following re-implementation of advance() makes a copy of a Date object using a de-referenced this but moved on 1 day

Date Date::advance()Date Date::advance(){{

Date d=*this;Date d=*this; // make a copy// make a copyd.julien++;d.julien++;return d;return d;

}}

Date d(1,9,1998);Date d(1,9,1998);Date new_d=d.advanceDate new_d=d.advance();();

• Thus, a completely new initialized Date object is produced

Date d

1/9/98

Date new_d

2/9/98

Friends

• A function or a class can be made a friend of another class– This means that the function or class

members can access the private members of the class

• Using the friend keyword in a class declaration allows encapsulation to be broken and should be used carefully

• This declaration allows func() and all of Y’s member functions to access the private parts of class X

• Note that it is the designer of class X who specifies the friend relationships

class Xclass X{{

..friend int func();friend int func();friend class Y;friend class Y;..

};};

class Dateclass Date{{

private :private :int d,m,y;int d,m,y;

  public :public :

Date(int,int,int);Date(int,int,int); // constr.// constr...

friend int weekend(Date);friend int weekend(Date);}; };   int weekend(Date date)int weekend(Date date){{

return ((date.d==0)||(date.d==6));return ((date.d==0)||(date.d==6)); // OK!// OK!}}

Static class members• Each object has its own copy of all non-static

date members of a class

• A static class members belongs to the class

– There is only 1 class wide copy

– Useful for maintaining class wide information

– static class data members exist even if an object hasn’t been instantiated

• static class members still have private, public privileges – Only static public member functions can access static

private members if an object has yet to be instantiated

– In this case the member function is accessed through the class name using the :: operator

– Once an object has been instantiated, static members can be accessed through non-static public member functions also

• static class members must be initialized once and once only before use

• A static class member num_objects can be used to keep a track on the number of objects of a certain class that have been created

class myClassclass myClass{{

private :private :static int num_objects;static int num_objects;  

public :public : myClass() { num_objects++;}myClass() { num_objects++;}

static int get() { return num_objects;}static int get() { return num_objects;}}; };

int myClass::num_objects=0;int myClass::num_objects=0; // Initialize static// Initialize static

void main()void main(){{

printf(“num objects so far = %d ”, myClass::get()); // prints 0printf(“num objects so far = %d ”, myClass::get()); // prints 0

myClass m1;myClass m1;myClass m2;myClass m2;myClass m3=new myClass();myClass m3=new myClass();

printf(“num objects so far = %d ”, myClass::get());printf(“num objects so far = %d ”, myClass::get()); // prints 3// prints 3

}}

And finally ……..• The key message in this lecture is

encapsulation and implementation/interface separation

• This leads to self-contained software units – classes – which are the basis of object oriented programming

• Object oriented applications comprise a set of objects, interacting through their class interfaces

• The next lecture looks at inheritance and polymorphism which allow for flexible object behaviour, a key element of OOP

top related