Presentation is loading. Please wait.

Presentation is loading. Please wait.

Programming Principles II Lecture Notes 6.1 Object Oriented Programming Andreas Savva.

Similar presentations


Presentation on theme: "Programming Principles II Lecture Notes 6.1 Object Oriented Programming Andreas Savva."— Presentation transcript:

1 Programming Principles II Lecture Notes 6.1 Object Oriented Programming Andreas Savva

2 2 Objects An object is simply a self-contained entity that has an existence independent of other entities. An object is simply a self-contained entity that has an existence independent of other entities. a pencil a pencil a book a book a car a car a basketball a basketball a watch a watch a house a house

3 3 A class can be regarded as the general form of an object: A class can be regarded as the general form of an object: The Tower Bridge in London belongs to the class of bridges; The Tower Bridge in London belongs to the class of bridges; The Bran Castle (Dracula’s castle in Rumania) belongs to the class of castles; The Bran Castle (Dracula’s castle in Rumania) belongs to the class of castles; Barack Obama belongs to the class of USA presidents or to the class of humans; Barack Obama belongs to the class of USA presidents or to the class of humans; Lionel Messi belongs to the class of football players; Lionel Messi belongs to the class of football players; The Land Rover Defender 90 TDI 4WD with RegNo CAA236 belongs to the class of cars; The Land Rover Defender 90 TDI 4WD with RegNo CAA236 belongs to the class of cars; Objects and Classes

4 4 Attributes and Operations Properties of the class Employ: Properties of the class Employ: Attributes and operations are called members of a class. Attributes and operations are called members of a class. Attributes are called data members. Attributes are called data members. Operations are called member functions. Operations are called member functions. AttributesOperations NameHire Employee Number Promote Job title Give pay rise SalaryFire Years of employment

5 5 Abstract Data Types (ADT) Data cannot be accessed directly. Data cannot be accessed directly. Data can only be accessed indirectly via the subprograms (member functions) associated with the data. Data can only be accessed indirectly via the subprograms (member functions) associated with the data. Thus, the class contains: The data structure. Subprograms to access and/or modify the data structure.

6 6 Information Hiding A client (user program) does not need to know how the data are actually stored or how the methods are programmed. This important programming strategy is called information hiding. A client (user program) does not need to know how the data are actually stored or how the methods are programmed. This important programming strategy is called information hiding. Data members and member functions (methods) available to a client are called public. Data members and member functions (methods) available to a client are called public. Private variables and member functions (functions) may be used in the implementation of the class, but are not available to a client. Private variables and member functions (functions) may be used in the implementation of the class, but are not available to a client. Methods of a class are public Functions in a class are private

7 7 Example – Abstract Data Type Main activities for operating a car are: Main activities for operating a car are: steering, accelerating, braking steering, accelerating, braking The design of a car can be viewed as an ADT with operations: The design of a car can be viewed as an ADT with operations: steer, accelerate, brake steer, accelerate, brake Two cars may implement these operations in different ways. Two cars may implement these operations in different ways. Most drivers can operate any car since the ADT presents a uniform method of operation. Most drivers can operate any car since the ADT presents a uniform method of operation.

8 8 C++ Class Declaration class Name { public: // Public members go here (internal to the class) private: // Private members go here (visible from outside) };

9 9 The Class Time class Time { public: void setTime(int, int, int); void print24hour(); void print12hour(); private: void twoDigits(int); int hour; int minute; int second; };

10 10 Member Functions void Time::setTime(int h, int m, int s) { hour = h; minute = m; second = s; } void Time::print24hour() { twoDigits(hour); cout << ’:’ ; twoDigits(minute); cout << ’:’ ; twoDigits(minute); cout << ’:’ ; twoDigits(second); cout << endl; } void Time::print12hour() { int h = (hour % 12 == 0 ? 12 : hour % 12); twoDigits(h); cout << ’:’; twoDigits(minute); cout << ’:’; twoDigits(minute); cout << ’:’; twoDigits(second); twoDigits(second); if (hour < 12) cout << ” am” << endl; else cout << ” pm” << endl; } void Time::twoDigits(int n) { if (n < 10) cout << ’0’; cout << n; }

11 11 Creating and Using Objects int main() { Time t; Time t; t.setTime(16,23,5); t.setTime(16,23,5); cout << "The time in 24 hour format is: "; t.print24hour(); t.print24hour(); cout << "The time in 12 hour format is: "; cout << "The time in 12 hour format is: "; t.print12hour(); t.print12hour(); cout << endl; cout << endl; return 0; return 0;} The time in 24 hour format is 16:23:05 The time in 12 hour format is 04:23:05 pm 23minute 16hour t5 second

12 12 Defining Functions in the Class class Time { public: void setTime(int h, int m, int s) { hour = h; minute = m; second = s; } void print24hour(); void print12hour(); private: void twoDigits(int n) { if (n < 10) cout << ’0’; cout << n; } int hour; int minute; int second; };

13 13 Constant Member Functions class Time { public: void setTime(int, int, int); void print24hour() const; void print12hour() const; private: void twoDigits(int) const; int hour; int minute; int second; }; void Time::print12hour() const { hour = hour % 12; // ERROR } In constant member functions we cannot change the values of data members. In constant member functions we cannot change the values of data members.

14 14 Mutable Data Members class Time { public: void setTime(int, int, int); void print24hour() const; void print12hour() const; private: void twoDigits(int) const; mutable int hour; int minute; int second; }; void Time::print12hour() const { hour = hour % 12; // CORRECT } Mutable data members can change their values in constant member functions. Mutable data members can change their values in constant member functions.

15 15 The Class Team class Team { public: Team(); // Constructor Team(char*, int = 0, int = 0, int = 0); // Constructor Team(const Team&); // Constructor void Setname(char*); void Print() const; void GamePlayed(int, int); ~Team(); // Destructor private: int Points() const; char name[20]; int wins; int draws; int losses; };

16 16 Member Functions void Team::Setname(char *s) { strcpy(name, s); } void Team::GamePlayed(int teamGoals, int opponentsGoals) { if (teamGoals > opponentsGoals) wins++; else if (teamGoals == opponentsGoals) draws++; else losses++; } void Team::Print() const { cout << name << " " << Points() << endl; cout << name << " " << Points() << endl;} int Team::Points() const { return wins * 3 + draws * 1 + losses * 0; return wins * 3 + draws * 1 + losses * 0;}

17 17 Constructors Special functions – have the name of the class Special functions – have the name of the class Called automatically when an object of the class is instantiated Called automatically when an object of the class is instantiated Do not return a value (no return type is specified) Do not return a value (no return type is specified) Their purpose is to initialize the object’s attributes Their purpose is to initialize the object’s attributes Team::Team(){ strcpy(name, ""); strcpy(name, ""); wins = 0; wins = 0; draws = 0; draws = 0; losses = 0; losses = 0;}

18 18 Creating and Using Objects int main() { Team ManUtd, Liv; Team ManUtd, Liv; ManUtd.Setname(”Manchester United”); ManUtd.Setname(”Manchester United”); Liv.Setname(”Liverpool FC”); Liv.Setname(”Liverpool FC”); ManUtd.GamePlayed(3, 2); ManUtd.GamePlayed(3, 2); Liv.GamePlayed(2, 2); ManUtd.Print(); ManUtd.Print(); Liv.Print(); return 0; } Manchester United 3 Liverpool FC 1

19 19 Overloading the Constructor class Team { public: Team(); Team(char *, int = 0, int = 0, int = 0);..... private:..... };Team::Team(){ strcpy(name, ""); strcpy(name, ""); wins = 0; wins = 0; draws = 0; draws = 0; losses = 0; losses = 0;} Team::Team(char *s, int w, int d, int l) { strcpy(name, s); strcpy(name, s); wins = w; wins = w; draws = d; draws = d; losses = l; losses = l;} Default values

20 20 Objects int main() { Team ManUtd(”Manchester United”, 3, 2, 1); Team ManUtd(”Manchester United”, 3, 2, 1); ManUtd.Print(); ManUtd.Print(); Team Liv(”Liverpool FC”, 2); Team Liv(”Liverpool FC”, 2); Liv.GamePlayed(2, 2); Liv.Print(); Team Arsenal = Liv; Arsenal.Setname(”Arsenal FC”); Arsenal.Print(); Team *RMadrid = new Team(”Real Madrid”, 7, 1); RMadrid->Print(); return 0; } Manchester United 11 Liverpool FC 7 Arsenal FC 7 Real Madrid 22

21 21 The Copy Constructor class Team { public: Team(); Team(char*, int = 0, int = 0, int = 0); Team(const Team&);..... private:..... }; Team::Team(const Team &tm) { strcpy(name, tm.name); strcpy(name, tm.name); wins = tm.wins; wins = tm.wins; draws = tm.draws; draws = tm.draws; losses = tm.losses; losses = tm.losses;} int main() { Team Barcelona(”Barselona FC”, 8); Team Olympiakos(Barcelona); Olympiakos.Setname(”Olympiakos”); Olympiakos. GamePlayed(2,2); Olympiakos.Print();Barcelona.Print(); return 0; } Olympiakos 25 Barcelona FC 24

22 22 The Destructor class Team { public:..... ~Team(); private:..... };Team::~Team(){ cout << name << ” is deleted\n” ; cout << name << ” is deleted\n” ;} Functions that are called whenever an object is deleted (e.g. goes out of scope) Functions that are called whenever an object is deleted (e.g. goes out of scope) Its purpose is to perform any necessary cleanup operations Its purpose is to perform any necessary cleanup operations Has no return type Has no return type Does not return a value Does not return a value

23 23 Objects and Destructor int main() { Team ManUtd(”Manchester United”, 3, 2, 1); Team ManUtd(”Manchester United”, 3, 2, 1); Team Liv(”Liverpool FC”, 2); Team Liv(”Liverpool FC”, 2); Team *RMadrid = new Team(”Real Madrid”, 7, 1); delete RMadrid; Team Cyprus[2]; Cyprus[0].Setname(”Omonoia”);Cyprus[1].Setname(”APOEL”); return 0; } Real Madrid is deleted APOEL is deleted Omonoia is deleted Liverpool FC is deleted Manchester United is deleted

24 24 The Initializer List C++ provides an alternative method of initialization, called initializer list. C++ provides an alternative method of initialization, called initializer list. Team::Team(char *s, int w, int d, int l) : wins(w), draws(d), losses(l) // initializer list { strcpy(name, s); // cannot specify initializer for arrays strcpy(name, s); // cannot specify initializer for arrays}

25 25 Pointers in Classes If a class object comes into existence dynamically using the new operator, the destructor must be called when this object is destroyed using the delete operator. If a class object comes into existence because it is a local variable in a function, the destructor will be called when the function returns. If a class object comes into existence dynamically using the new operator, the destructor must be called when this object is destroyed using the delete operator. If a class object comes into existence because it is a local variable in a function, the destructor will be called when the function returns. class Vect { public: Vect(int size = 5) { Vect(int size = 5) { vectSize = size; vectSize = size; theVect = new int[size]; theVect = new int[size]; } //... //... ~Vect() { ~Vect() { delete [] theVect; delete [] theVect; }private: int vectSize; int* theVect; };

26 26 The Assignment statement { Vect a(10);// a is a vector of size 10 { Vect b;// c is a vector of default size 5 b = a;// assign a to b (DANGER) }// the destructor for b will be executed..... } ?????????? 0123456789 ?????01234 theVect 10vectSize a theVect 5vectSize b10

27 27 Copy Constructor & Assignment Operator The assignment operator deletes the existing array storage, allocates a new array of the proper size, and copies the elements into this array. The if-statement checks against the possibility of self assignment (a = a). This is done using the “this” keyword. For any class object, this is a pointer to the address of the object. The assignment operator deletes the existing array storage, allocates a new array of the proper size, and copies the elements into this array. The if-statement checks against the possibility of self assignment (a = a). This is done using the “this” keyword. For any class object, this is a pointer to the address of the object. Vect::Vect(const Vect &a) { vectSize = a.vectSize; vectSize = a.vectSize; theVect = new int[vectSize]; theVect = new int[vectSize]; for (int i=0;i { "@context": "http://schema.org", "@type": "ImageObject", "contentUrl": "http://images.slideplayer.com/14/4224189/slides/slide_27.jpg", "name": "27 Copy Constructor & Assignment Operator The assignment operator deletes the existing array storage, allocates a new array of the proper size, and copies the elements into this array.", "description": "The if-statement checks against the possibility of self assignment (a = a). This is done using the this keyword. For any class object, this is a pointer to the address of the object. The assignment operator deletes the existing array storage, allocates a new array of the proper size, and copies the elements into this array. The if-statement checks against the possibility of self assignment (a = a). This is done using the this keyword. For any class object, this is a pointer to the address of the object. Vect::Vect(const Vect &a) { vectSize = a.vectSize; vectSize = a.vectSize; theVect = new int[vectSize]; theVect = new int[vectSize]; for (int i=0;i

28 The Class 28 class Vect { public: Vect(int size = 5) { Vect(int size = 5) { vectSize = size; vectSize = size; theVect = new int[size]; theVect = new int[size]; } //... //... ~Vect() { ~Vect() { delete [] theVect; delete [] theVect; } Vect(const Vect&); Vect(const Vect&); Vect& operator=(const Vect&); Vect& operator=(const Vect&);private: int vectSize; int* theVect; };

29 29 The String Example class String { public: String(int = 20); String(char*); void Display(); ~String();private: int len; char *s; }; String::String(int n) { len = n; s = new char[n]; s[0] = '\0'; } String::String (char *str) { len = strlen(str) + 1; s = new char[len]; strcpy(s,str);} String::~String() { delete [] s; } void String::Display () { cout << s << endl; }

30 30 Classes Vs. Structs class Time { public: int hour; int minute; int second; Time(); Time(int, int, int); }; Time::Time() { hour = minute = second = 0; } Time::Time(int h, int m, int s) { hour = h; minute = m; second = s; } struct Time { int hour; int minute; int second; Time(); Time(int, int, int); }; Time::Time() { hour = minute = second = 0; } Time::Time(int h, int m, int s) { hour = h; minute = m; second = s; } class: Default is private struct: Default is public

31 31 Overloading Operators C++ allows operators overloading, such as +, *, +=, and <<. The definition is similar to a function, but in place of a function name we use “operator==”. In general, the == is replaced by the operator to be defined. For binary operators we have two arguments, and for unary operators we have just one. C++ allows operators overloading, such as +, *, +=, and <<. The definition is similar to a function, but in place of a function name we use “operator==”. In general, the == is replaced by the operator to be defined. For binary operators we have two arguments, and for unary operators we have just one. struct ComplexNum { ComplexNum(float r, float i) { real = r; imaginary = i; }..... friend bool operator==(const ComplexNum&, const ComplexNum&); private: float real; float imaginary; }; bool operator==(const ComplexNum &a, const ComplexNum &b) { return a.real == b.real && a.imaginary == b.imaginary; return a.real == b.real && a.imaginary == b.imaginary;} void main() { ComplexNum N1(3, 12);// 3 + 12i ComplexNum N1(3, 12);// 3 + 12i ComplexNum N2(-2, 1);// -2 + i ComplexNum N2(-2, 1);// -2 + i cout << (N1==N2);// output 0 (false) cout << (N1==N2);// output 0 (false)}

32 32 Overloading Operators Another useful application is defining input and output operators for classes and structures. Here is how to define an output operator for the ComplexNum structure. The type ostream is the system’s output structure. The standard output, cout is of this type. Another useful application is defining input and output operators for classes and structures. Here is how to define an output operator for the ComplexNum structure. The type ostream is the system’s output structure. The standard output, cout is of this type. struct ComplexNum { ComplexNum(float r, float i) { real = r; imaginary = i; }..... friend bool operator==(const ComplexNum&, const ComplexNum&); friend ostream& operator<<(ostream&, const ComplexNum &); private: float real; float imaginary; }; ostream& operator<<(ostream &out, const ComplexNum &a) { out =0 ? ’+’ : ’-’) =0 ? ’+’ : ’-’) << fabs(a.imaginary) << ’i’; return out; return out;} void main() { ComplexNum N1(3, 12); ComplexNum N1(3, 12); cout << N1;// output 3+12i cout << N1;// output 3+12i}

33 33 Matrix Operations A complete program #include using namespace std; const int MAX = 10; enum Error_code {fail, success}; class Matrix { public: Matrix(); void ReadMatrix(); void DisplayMatrix() const; Error_code AddSubtract(char, const Matrix&, const Matrix&); Error_code Multiply(const Matrix&, const Matrix&); private: int row, col; float entry[MAX][MAX]; };

34 34 Constructor & ReadMatrix Matrix::Matrix() { row = col = 0; } void Matrix::ReadMatrix() { cout << ”Enter number of rows and colums: ”; cin >> row >> col; if (row > MAX || col > MAX) row = col = 0; else { cout << ”Enter the ” << row << ”x” << col << ” matrix elements\n”; for (int i = 0; i < row; i++) for (int j = 0; j < col; j++) cin >> entry[i][j]; } cout << endl; }

35 35 DisplayMatrix & AddSubtract void Matrix::DisplayMatrix() const { for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) cout << setw(8) << fixed << setprecision(2) << entry[i][j]; cout << endl; } cout << endl << endl; } Error_code Matrix::AddSubtract(char c, const Matrix &A, const Matrix &B) { if (A.row != B.row || A.col != B.col) return fail; row = A.row; col = A.col; for (int i = 0; i < row; i++) for (int j = 0; j < col; j++) switch (c) { case ’+’ : entry[i][j] = A.entry[i][j] + B.entry[i][j]; break; case ’–’ : entry[i][j] = A.entry[i][j] – B.entry[i][j]; break; default : return fail; } return success; }

36 36 Multiply Error_code Matrix::Multiply(const Matrix &A, const Matrix &B) { if (A.col != B.row) return fail; row = A.row; col = B.col; for (int i = 0; i < row; i++) for (int j = 0; j < col; j++) { entry[i][j] = 0.0; for (int k = 0; k < A.col; k++) entry[i][j] += A.entry[i][k] * B.entry[k][j]; } return success; }

37 37 The main() void main() { int choice; do { cout << ”Enter 1 for addition, 2 for subtraction, 3 for multiplication: ”; cin >> choice; } while (choice 3); Matrix A, B, Result; A.ReadMatrix(); B.ReadMatrix(); Error_code outcome; switch (choice) { case 1 : outcome = Result.AddSubtract(’+’, A, B); break; case 2 : outcome = Result.AddSubtract(’–’, A, B); break; case 3 : outcome = Result.Multiply(A, B); break; } if (outcome == fail) cout << ”\nMatrices are not compatible\n”; else { cout << ”\nResult:\n\n” << flush; Result.DisplayMatrix(); }

38 Programming Principles II Lecture Notes 6.2 Inheritance Andreas Savva

39 39 Inheritance In a hierarchy of classes, the classes towards the top are known as “base classes” or “super classes”. Those further down are the “derived classes” or “sub-classes”. In a hierarchy of classes, the classes towards the top are known as “base classes” or “super classes”. Those further down are the “derived classes” or “sub-classes”. Derived classes are specialisations of base classes, sharing their properties but adding their own. Derived classes are specialisations of base classes, sharing their properties but adding their own. Motor Vehicles Motor BikesCars StreetChopper4 x 4Saloon 4 doors5 doors2 doors

40 40 Inheritance in C++ In object-oriented languages we can use classes that are already declared as base classes and derive specializations from them. In object-oriented languages we can use classes that are already declared as base classes and derive specializations from them. class Today { public: Today(); void setDate(int, int, int); void Tomorrow(); void displayDate() const; protected: int day; int month; int year; private: char day_str[15]; char month_str[15]; }; class Calendar:public Today { public: Calendar(); void AddBirthday(); void DeleteBirthday(); void printTodayBirthday() const; void displayDate() const; private: int birthdaySize[366]; char birthday[366][10][30]; };

41 41 Derived Classes methods: Today (constructor) setDate Tomorrow displayDate data members: day month year day_str month_str class Today methods: Calendar (constructor) setDate Tomorrow AddBirthday DeleteBirthday printTodayBirthday displayDate data members: day month year birthdaySize birthday class Calendar Base class Derived class

42 42 Public Inheritance class Today { public: Today(int, int, int); void setDate(int, int, int); void Tomorrow(); void displayDate() const; protected: int day; int month; int year; private: char day_str[15]; char month_str[15]; }; class Calendar:public Today { public: Calendar(int, int, int); void AddBirthday(); void DeleteBirthday(); void printTodayBirthday() const; void displayDate() const; private: int birthdaySize[366]; char birthday[366][10][30]; }; PublicProtectedPrivate CalendardaybirthdaySize setDatemonthbirthday Tomorrowyear AddBirthday DeleteBirthday printTodayBirthday displayDate class Calendar

43 43 Protected Inheritance class Today { public: Today(int, int, int); void setDate(int, int, int); void Tomorrow(); void displayDate() const; protected: int day; int month; int year; private: char day_str[15]; char month_str[15]; }; class Calendar:protected Today { public: Calendar(int, int, int); void AddBirthday(); void DeleteBirthday(); void printTodayBirthday() const; void displayDate() const; private: int birthdaySize[366]; char birthday[366][10][30]; }; PublicProtectedPrivate CalendarsetDatebirthdaySize AddBirthdayTomorrowbirthday DeleteBirthdayday printTodayBirthdaymonth displayDateyear class Calendar

44 44 Private Inheritance class Today { public: Today(int, int, int); void setDate(int, int, int); void Tomorrow(); void displayDate() const; protected: int day; int month; int year; private: char day_str[15]; char month_str[15]; }; class Calendar:private Today { public: Calendar(int, int, int); void AddBirthday(); void DeleteBirthday(); void printTodayBirthday() const; void displayDate() const; private: int birthdaySize[366]; char birthday[366][10][30]; }; PublicProtectedPrivate CalendarsetDate AddBirthdayTomorrow DeleteBirthdayday printTodayBirthdaymonth displayDateyear birthdaySize birthday class Calendar

45 45 Calling the base class constructor from the derived class Calendar::Calendar(int d, int m, int y) : Today(d, m, y) { for (int i=0; i<366; i++) birthdaySize[i] = 0; } The constructor Today (with parameter values from the parameters of Calendar ) is invoked by placing it in a member initialization list. The constructor Today (with parameter values from the parameters of Calendar ) is invoked by placing it in a member initialization list. If there has been a base class that requires no parameters, then the compiler would ensure that it would be called automatically, before the derived class constructor. If there has been a base class that requires no parameters, then the compiler would ensure that it would be called automatically, before the derived class constructor. However, even if no parameters are required, it does not harm to invoke the base class constructor explicitly, as above. However, even if no parameters are required, it does not harm to invoke the base class constructor explicitly, as above.

46 46 Base class enum hourType {unknown, format12, format24}; class Time { public: Time(int, int, int); void DisplayTime() const; protected: int hour, min, sec; hourType hour_type; }; Time::Time(int h, int m, int s) : hour(h), min(m), sec(s) { hour_type = unknown; } void Time::DisplayTime() const { cout << hour << ’\n’ << min << ’\n’ << sec << endl; } 16 12 36

47 47 Derived classes class Time24:public Time { public: Time24(int, int, int); void DisplayTime() const; }; Time24::Time24(int h, int m, int s) : Time(h, m, s) { hour_type = format24; } void Time24::DisplayTime() const { cout << hour << ’:’ << min << ’:’ << sec << endl; } class Time12:public Time { public: Time12(int, int, int); void DisplayTime() const; }; Time12::Time12(int h, int m, int s) : Time(h, m, s) { hour_type = format12; } void Time12::DisplayTime() const { int h = (hour % 12 == 0 ? 12 : hour % 12); cout << h << ’:’ << min << ’:’ << sec; cout << (hour < 12 ? ” am” : ” pm”) << endl; } 4:12:36 pm16:12:36

48 48 Objects of Derived classes int main() { Time24 t1(15, 29, 30); Time12 t2(22, 30, 45); t1.DisplayTime(); t2.DisplayTime(); return 0; } 15:29:30 10:30:45 pm

49 49 Arrays of Mixed Object Types int main() { Time* t[2]; t[0] = new Time24(15, 29, 30); t[1] = new Time12(22, 30, 45); t[0]->DisplayTime(); t[1]->DisplayTime(); return 0; } 15 29 30 22 30 45 The problem with arrays is that each of its members must be of the same type. The problem with arrays is that each of its members must be of the same type. However, we can declare an array of pointers to the base class and assign objects of deferent derived classes to it. However, we can declare an array of pointers to the base class and assign objects of deferent derived classes to it. It must be noted however that the function DisplayTime executed is the one belonging to the base class. It must be noted however that the function DisplayTime executed is the one belonging to the base class.

50 50 Polymorphism Polymorphism means having many shapes and it refers to the ability to use the same name to perform different functions in different classes. Polymorphism means having many shapes and it refers to the ability to use the same name to perform different functions in different classes. One form of polymorphism is overloading functions. One form of polymorphism is overloading functions. Another one is by using virtual functions in the base classes. Another one is by using virtual functions in the base classes. class Time { public: Time(int, int, int); virtual void DisplayTime() const; protected: int hour, min, sec; hourType hour_type; }; Time::Time(int h, int m, int s) : hour(h), min(m), sec(s) { hour_type = unknown; } void Time::DisplayTime() const { cout << hour << ’\n’ << min << ’\n’ << sec << endl; }

51 51 Virtual Functions int main() { Time* t[3]; t[0] = new Time(8, 16, 12); t[1] = new Time24(15, 29, 30); t[2] = new Time12(22, 30, 45); t[0]->DisplayTime(); // from base class Time t[1]->DisplayTime(); // from derived class Time24 t[2]->DisplayTime(); // from derived class Time12 delete []t; return 0; } 8 16 12 15:29:30 10:30:45 pm One of the key features of derived classes is that a pointer to a derived class is type-compatible with a pointer to its base class. One of the key features of derived classes is that a pointer to a derived class is type-compatible with a pointer to its base class. With non-virtual functions the compiler contains a specific reference to the function (static binding). With non-virtual functions the compiler contains a specific reference to the function (static binding). With virtual functions the compiler produces code that will invoke the correct function for the object that is being referred to while the program is running (dynamic binding). With virtual functions the compiler produces code that will invoke the correct function for the object that is being referred to while the program is running (dynamic binding).

52 52 Abstract Base Classes and Pure Virtual Functions An abstract base class is a class that has at least one pure virtual function. An abstract base class is a class that has at least one pure virtual function. A pure virtual function is defined by appending “= 0” to the function declaration and has no function definition. A pure virtual function is defined by appending “= 0” to the function declaration and has no function definition. class Time { public: Time(int, int, int); virtual void DisplayTime() const = 0; protected: int hour, min, sec; hourType hour_type; }; Time::Time(int h, int m, int s) : hour(h), min(m), sec(s) { hour_type = unknown; } // DisplayTime() cannot be defined

53 53 Abstract Base Classes int main() { Time24 t24(15, 29, 30); Time12 t12(22, 30, 45); Time* time1 = &t24; Time* time2 = &t12; time1->DisplayTime(); // from derived class Time24 time2->DisplayTime(); // from derived class Time12 return 0; } 15:29:30 10:30:45 pm The main difference between an abstract base class and a regular polymorphic class is that, because in abstract base classes at least one of its members lacks implementation, instances (objects) of that class cannot be created, i.e. The main difference between an abstract base class and a regular polymorphic class is that, because in abstract base classes at least one of its members lacks implementation, instances (objects) of that class cannot be created, i.e. Time t; 

54 54 Class Friends and Class Members class Matrix; // Matrix prototype – Not necessary class Vector { // a 3-element vector public:..... friend class Matrix; // allow Matrix access to coord friend ostream& operator<<(ostream&, const Vector&); private: double coord[3]; }; class Matrix { // a 3x3 array public:..... Vector multiplyBy(const Vector& v) { // multiply (a * v) Vector w(0,0,0); for (int i=0;i<3;i++) for (int j=0;j<3;j++) w.coord[i] += a[i][j] * v.coord[j]; return w; } private: double a[3][3]; }; Complex data structures typically involve the interaction of many different classes. Complex data structures typically involve the interaction of many different classes. Private members of a class may only be accessed from within the class, but also from a friend (a function or another class). Private members of a class may only be accessed from within the class, but also from a friend (a function or another class). Vector is a friend of Matrix but Matrix is not a friend of Vector The output operator can now access the private member data

55 55 Functions Friends to Classes class team { public:..... friend int main(); // allow main() to access data members private: int wins, draws, losses; }; int main() { team Liverpool(5,2,1); int points = 3 * Liverpool.wins + Liverpool.draws; cout << ”Liverpool has ” << points << ” points”; return 0; }

56 56 Nesting Classes and Types within Classes class Complex { private: class Node { //... (Node definition here) } //... (Remainder of complex definition) }; A class definition can be nested within another class. A class definition can be nested within another class. In the example below only the Complex class can use the Node class. We can also embed other sorts of user-defined entities inside the class definition, such as enumerations, structures, and typedefs. In the example below only the Complex class can use the Node class. We can also embed other sorts of user-defined entities inside the class definition, such as enumerations, structures, and typedefs.

57 Class Templates Classes can have members that use template parameters as types. Classes can have members that use template parameters as types. 57 template class myPair { T values[2]; public: myPair(T first, T second) { values[0] = first; values[1] = second; } }; myPair A(123, 62); myPair B(3.0, 2.34);

58 Member Functions Outside In case member functions are defined outside the declaration of the class template, they must always precede their definition with the template prefix. In case member functions are defined outside the declaration of the class template, they must always precede their definition with the template prefix. 58 template class myPair { T a, b; public: myPair(T, T); T GetMax(); }; template myPair ::myPair(T first, T second) { a = first; b = second; } template T myPair ::GetMax() { T result; result = a>b? a : b; return result; }

59 Classes as Formal Parameters 59 template class myPair { T a, b; public: myPair(T first, T second) {a=first; b=second;} bool Same(myPair) const; }; template bool myPair ::Same(myPair original) const { return a == original.a && b==original.b; }

60 Classes in Classes with Templates 60 template class Vector { W point[3]; template friend class Vertices; public: Vector(){point[0]=0;point[1]=0;point[2]=0;}... }; template class Vertices { Vector curve[100]; public:... void print() { for (int i=0;i<100; i++) { for (int d=0; d<3; d++) cout << curve[i].point[d] << '\t'; cout << endl; } };

61 Template Specialization 61 template class myContainer {...}; template <> class myContainer {...}; A different implementation to a template can be defined when a specific type is passed as a template parameter. To do this a specialization of that template must be declared. A different implementation to a template can be defined when a specific type is passed as a template parameter. To do this a specialization of that template must be declared. Class template Class template specialization When specializations for a template class are declared, all its members, even those exactly the same to the generic template class, must be defined. The reason to this is that there is no “inheritance” of members from the generic template to the specialization. When specializations for a template class are declared, all its members, even those exactly the same to the generic template class, must be defined. The reason to this is that there is no “inheritance” of members from the generic template to the specialization.

62 Template Specialization - Example 62 template class myContainer { T element; public: myContainer(T arg){element = arg;} T increase() {return ++element); }; template <> class myContainer { char element; public: myContainer(char arg){element = arg;} char uppercase() { if (element>=’a’ && elsement<=’z) element += ’A’ – ’a’; return element; } }; Different implementation for characters

63 Template Specialization - Example 63 int main() { myContainer myint(12); myContainer mychar(’d’); cout << myint.increase() << endl; cout << mychar.uppercase() << endl; return 0; }; 13 D

64 Non-Type parameters for Templates 64 template class mySequence { T elements[N]; public: void setElement(int n, T value); T getElement(int x); }; template void mySequence ::setElement(int x, T value) { elements[x] = value; } template T mySequence ::getElement(int x) { return elements[x]; } Besides the template arguments that are preceded by the keywords “class” or “typename” which represent types, templates can also have regular parameters, similar to those found in functions. Besides the template arguments that are preceded by the keywords “class” or “typename” which represent types, templates can also have regular parameters, similar to those found in functions.

65 Non-Type parameters for Templates 65 int main() { mySequence myints; mySequence myreals; myints.setElement(0, 87); myreals.setElement(3, 3.14159); cout << myints.getElement(0) << endl; cout << myreals.getElement(3) << endl; return 0; } 87 3.14159 template class mySequence {...}; mySequence<> myseq; mySequence myseq; It is also possible to set default values or types for class template parameters, i.e. and create objects by declaring: which is equivalent to:


Download ppt "Programming Principles II Lecture Notes 6.1 Object Oriented Programming Andreas Savva."

Similar presentations


Ads by Google