Constant Objects and Constant Class Members Friend Functions
Constant Objects and Constant Class Members Friend Functions and Friend Classes Static attributes and Static methods A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 1
Constant object, methods and attributes • In this lecture we want to bring the concept of constant to object-oriented design • Before explaining the constant objects, we need to introduce constant methods and constant attributes A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 2
Constant Methods • A constant method of a class cannot modify any attribute of that class. It can only print or access the values for read purpose only. • Consider the following example: class Test { private: int x, y; public: void input(); void print() const; } <See: Example 1> A. R. Hadaegh Dr. Ahmad R. Hadaegh void Test: : input() { cout << “enter x: ”; cin >> x; cout << “enter y: ”; cin >> y; { void Test: : print() const { cout << “x is: ” << x << endl; cout << “y is: ” << y << endl; { California State University San Marcos (CSUSM) Page 3
• Any method that is not constant is considered as a nonconstant method in a class. • It is always assumed that a non-constant method may change the state (value) of the attributes of the abject • A constant method can only invoke (call) other constant methods and not non-constant methods. • However, a non-constant method can invoke either a constant method or a non-constant method. • Any method in a class except constructor and destructor can be declared constant A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 4
Constant Attribute (Data members) • A constant attribute is an attribute in which once it is initialized to certain value, its value can not be modified again. • To declare a constant attribute, we place the word constant just before the declaration of the attribute. • For example, to declare a constant attribute called Gender of type char, we can do as follows: const char Gender; A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 5
class Child { public: Child(); // empty, default constructor Child(char sex, string The. Name); void print(); private: const char Gender; // can’t initialize Gender in here!! double Weight. At. Birth; double Hieght. At. Birth; string Name; }; • One can’t initialize constant data members in the class definition. How can we give the Gender data member the desired default value? A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 6
• Use the member initialization list to initialize data member when an object is constructed. Child: : Child() : Gender('B') // initialization list { Weight. At. Birth = 8. 2; // in pound Hieght. At. Birth = 20; // in inch Name = "Jim"; } • You must use the above syntax, the member name and the value specified in parenthesis. A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 7
• You can also use a value passed in the constructor argument list to initialize data members in the initialization list. Child: : Child(char sex, string The. Name): Gender(sex) { Weight. At. Birth = 8. 2; Hieght. At. Birth = 20; Name = The. Name; } <See: Example 2> A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 8
• If more than one member is to be initialized, separate the members in the initialization list by commas. For example, class Child { public: Child(){}; Child(char sex, string The. Name); void print(); private: const char Gender; const double Weight. At. Birth; const double Hieght. At. Birth; string Name; }; Child: : Child(char sex, string The. Name): Gender(sex), Weight. At. Birth(8. 2), Hieght. At. Birth(20) { Name = The. Name; } <See: Example 3> A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 9
• It is also possible to initialize non-constant data members right at the initialization list. For example: class Child { public: Child(){}; Child(char sex, string the. Name); void print(); private: const char Gender; const double Weight. At. Birth; const double Hieght. At. Birth; string Name; }; Child: : Child(char sex, string The. Name): Gender(sex), Weight. At. Birth (8. 2), Hieght. At. Birth(20) , Name(the. Name) { } <See: Example 4> A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 10
Constant Objects • A constant object is an object that once it is declared, the values of its attributes cannot be changes any more. • Once a constant object is declared, the constructor is called automatically to initialize the attributes of that object • After that, a constant object can only invoke (call) it’s constant methods and any of its non-constant methods. • When a not constant object goes out of scope, its destructor is called. • Constructor and destructors are the only non-constant methods that a constant object can invoke. These invocations are done by the system. A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 11
Consider the following class definition: class Time { public: Time(); void set_time( int h, int m, int s ); void print_time() const; private: int hour; // 0 -23 int minute; // 0 -59 int second; // 0 -59 }; //----------------------Time: : Time() { hour = 12; minute = 0; second = 0; } void Time: : set_time( int h, int m, int s ) { // if time not valid set to 0: 0: 0 hour = minute = second = 0; if (( h >= 0) && (h <=23 )) hour = h; if (( m >= 0) && (m <=59 )) minute = m; if (( s >= 0) && (s <=59) ) second = s; } //---------------------------void Time: : print_time() const { cout << hour << ": " <<minute << ": " << second; if ( hour < 12 ) cout << " AM" << endl; else cout << " PM" << endl; } //---------------------!!!!Won’t compile int main() { const Time the. Time; the. Time. set_time(2, 30, 34); } the. Time. print_time(); This one is ok <See: Example 5> A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 12
Friend Functions and Friend Classes • A friend function is a function declared outside of class scope, i. e. it’s not a member function, yet has full access to all class members. Even private data members. • A stand alone function, a class function, or an entire class may be declared to be a friend to a class. • Friend functions are most commonly used to enhance performance. A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 13
• Friend functions are coupled to a class in that they are aware of implementation issues for the class. • To declare a friend function, include the function’s prototype in the class definition and precede it by the keyword friend. class Count { friend void set. X( Count &c, int val); public: Count() { x = 0; }; void print() { cout << x; }; private: int x; }; // non class function, has // access to private data since //it was declared to be a friend void set. X (Count& c, int val ) { c. x = val; } < See: Example 6> A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 14
• Friendship is granted by a class. For class B to be a friend of class A, class A must declare that class B is its friend. • Friendship is not symmetric or transitive. Because class A declares class B to be its friend does not mean class A is a friend to class B. • If class A is a friend of class B and class B is a friend of class C, it does not follow that class A is a friend of class C. • The next example declares a class to be a friend A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 15
class Class 1 { public: void foo (char c ); . . . private: int y; }; class Class 2 { friend Class 1; . . . private: int x; }; // all methods of Class 1 are friends of class 2 How about if Class 1 wants to make Class 2 as its friend as well? See the next example. A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 16
• Consider the following example: class Class 1 { friend Class 2; public: void foo (char c ); . . . private: int y; }; class Class 2 { friend Class 1; . . . private: int x; }; // all methods of Class 1 are friends of class 2 • Class 2 has to be defined before it can be considered to be a friend of Class 1. Similarly, Class 1 has to be defined before it can be considered to a be a friend of Class 2. A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 17
• To fix this problem, we need to make forward class declaration of the classes: class Class 1; class Class 2; class Class 1 { friend Class 2; public: void foo (char c ); . . . private: int y; }; class Class 2 { friend Class 1; . . . private: int x; }; A. R. Hadaegh Dr. Ahmad R. Hadaegh // all methods of Class 1 are friends of class 2 California State University San Marcos (CSUSM) Page 18
Forward Class Declaration • A forward class declaration can be thought of as being similar as a function prototype. It alerts the compiler that there is a class with that name. • You cannot create objects with a forward class declaration since the compiler doesn’t know what constructors are available. • However, you can declare a reference or a pointer variable to such a class. No object is created with a reference or a pointer variable. • However, you cannot access methods until the compiler sees the forward class’s full definition, usually in a header file. A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 19
Static Class Members • Normally each object has its own copy of all the data members. Also, to use a method one must usually specify the object and then the method name. • In C++ there is the concept of class-wide data members and class-wide methods. To access these members an object is not needed. • When a value belongs to the class, i. e. it is the same for all objects. • Use the keyword static to specify that a member is class wide. Static class members can be public or private. A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 20
class Tank { public: Tank(); ~Tank(); static int num_tanks() { return num. Tanks; }; . . . private: static int }; num. Tanks; • Static data members must be initialized once at file scope. Usually in the same file that implements the class methods: A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 21
int Tank: : num. Tanks = 0; Tank: : Tank() { num. Tanks ++; . . . } Tank: : ~Tank() { num. Tanks --; . . . } …. A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 22
A static method may be called without an object. For this case, we use the scope resolution operator. A static method may also be called via an object. int main() { cout << Tank: : num_tanks() << endl; Tank t 1; cout << Tank: : num_tanks() << endl; cout << t 1. num_tanks() << endl; . . . } < See: Example 7> A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 23
• you can invoke (call) static data members from any method in a class (static or none static methods). • However, static methods can only invoke other static methods. • Regular methods can access any data member, static or non-static. • However, static methods can only access static data members and not the non-static data members A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 24
this Pointer A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 25
The this Pointer - In C++ all objects of a class have their own copy of data members yet all objects use the same code for class methods. - The C++ compiler uses the this pointer to couple a method call with the object’s data members. class A { public: void set_x(int val); . . . private: int x; }; A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 26
void A: : set_x(int val) { x = val; }. . . main() { } A obj 1; A obj 2; obj 1. set_x(5); // changes obj 1’s data member obj 2. set_x(10); // changes obj 2’s data member - The this pointer, a pointer to the same type as the method’s class, is implicitly passed as an argument to the method by the compiler. A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 27
main() { } A A obj 1; obj 2; obj 1. set_x(&obj 1, 5); obj 2. set_x(&obj 2, 10); // pass address of obj 1 // pass address of obj 2 - Within the method the compiler implicitly dereferences the this pointer to access the data members. void A: : set_x(A* this, int val) { this->x = val; } - Even though the this pointer is not specified in the argument list it is accessible to the programmer. If you wish, you could use this syntax when implementing a method. A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 28
void A: : set_x(int val) { this->x = val; } or void A: : set_x(int val) { (*this). x = val; } A. R. Hadaegh Dr. Ahmad R. Hadaegh // parenthesis are important! California State University San Marcos (CSUSM) Page 29
Concatenating member function calls - If you declare a method to return a reference to an object of the same class, and you return the this pointer, then it’s possible to concatenate method calls. A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 30
class Time { public: Time(); Time& set_time( int h, int m=0, int s=0 ); Time& set_time( const Time &t ); void print_time() const; . . . Time& set_hour(int h); set_minute(int m); set_second(int s); private: . . . }; A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 31
Time& Time: : set_hour(int h) { if ( hr>=0 && hr<=23 ) hr = h; } return *this; . . . main() { } Time t; t. set_hour(15). set_minunte(30). print_time(); t. set_time(8, 30, 0). print_time(); A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 32
- This works because the member access operator, “. ”, associates from left to right. - “for the object on the left, access the member on the right” - Since t. set_hour(15) returns a Time&, the original this object, we can chain the next member access on what set_hour()returns. Thus: t. set_time(8, 30, 0). print_time(); A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 33
- first sets the time, set_time(8, 30, 0), which returns the this object, and for the this object call the print_time() method. - You could do the following as well but it means making a variable and doing an assignment. main() { Time t; Time& r = t. set_time(8, 30, 0); r. print_time(); } A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 34
Operator Overloading: Fundamentals, Restrictions, and Functions : Class Members or Friends A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 35
Fundamentals of Operator Overloading - C++ provides operators, functions which use a symbol as a name, to be used with primitive data types. - For example, the multiply function uses the ‘*’ operator on two operands. - C++ overloads these operators. The same operator name is uses with different operator types. - <float> * <float> will perform floating point arithmetic while <int> * <int> will perform integer arithmetic. - Also, the ‘*’ symbol can be used with a pointer variable. It performs the dereference operation on the pointer. - The ‘*’ has been overloaded yet again. A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 36
- The context, binary or unary operator, and the operator types determine which function should be performed. - C++ allows programmers to use the operator syntax on user defined data types. - Operator overloading, if used properly, can make code easier to read and understand. A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 37
class Complex. Number { private: float Real. Portion; float Image. Portion; public: // constructors Complex. Number(); Complex. Number(float, float); // other methods void Get. Real. Portion( ) { return(Real. Portion); } void Get. Image. Portion( ) { return(Image. Portion); } void add(const Complex. Number&, const Complex. Number&); Complex. Number operator+(const Complex. Number&, const Complex. Number&); }; A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 38
main(){ Complex. Number n 1(1, 0); Complex. Number n 2(1, 1); Complex. Number n 3; n 3 = n 1 + n 2; // with operator overloading Complex. Number tmp; tmp. add(n 1, n 2); // without operator overloading } - C++ does not allow you to create new operators, but you can overload existing operator to user defined data types as operands. - To overload an operator use the keyword operator, the operator symbol, and specify the data types of the operands. A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 39
Complex. Number operator+(const Complex. Number& n 1, const Complex. Number& n 2) { float r = n 1. Real. Portion + n 2. Real. Portion; float i = n 1. Image. Portion + n 2. Image. Portion; return Complex. Number(r, i); } A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 40
- To use an operator on class objects you must overload the operator yourself. Except for two operators ( =, &) which are provided automatically for every class. - The ‘=’ operator performs a shallow bit copy of right hand side (RHS) operand into the left hand side (LHS) operand. - The ‘&’ returns the address of the object. - Operator overloading is used to provide for code clarity. Some classes, mathematical classes, are naturals for mathematical operators. - Provide expected operator functionality. It would confuse clients if the ‘*’ operator performed an addition. A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 41
Restrictions on Operator Overloading - You cannot create new operators. For example, There is no ‘$’ operator in C++, you cannot use this symbol as an operator. - Not every operator may be overloaded, but most can. - Fig. 8. 1 (pg. 466) shows the operators that can be overloaded. - Fig. 8. 2 (pg. 467) shows the few operators that cannot be overloaded. They are: . A. R. Hadaegh Dr. Ahmad R. Hadaegh . * : : ? : California State University San Marcos (CSUSM) sizeof() Page 42
- You can only change the operand type for C++ operators - You cannot change the operator precedence. The ‘*’ operator gets called before the ‘+’ operator. - You cannot change the associativity of the operator. For example, the unary “not” operator, ‘!’, cannot be changed to <operand>! - Default arguments are not allowed. You cannot change the number of operands the operator needs. - You cannot overload the way C++ operators function with built in primitive data types. That is, you cannot overload <int> + <int>. A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 43
- You can only overload user defined data types or a mixture of user defined and primitive data types. <complex> + <int> + <complex> A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 44
Operator Functions: Class Members or Friends - Most operator functions may be class members or stand alone functions. For efficiency, non-class operator functions are made friends of the class Complex. Number { friend Complex. Number operator+(const Complex. Numer &n 1, const Complex. Number &n 2); public: …… }; - If the operator function is not a member function the first operand is the LHS, and the second operand is the RHS. A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 45
Complex. Number operator+(const Complex. Numer& lhs, const Complex. Number& rhs) { float r = lhs. Get. Real. Portion() + rhs. Get. Real. Portion() ; float i = lhs. Get. Image. Portion() + rhs. Get. Image. Portion() ; return Complex. Number(r, i); } Main() { Complex. Number n 1(1, 0); Complex. Number n 2(1, 1); Complex. Number n 3; n 3 = n 1 + n 2; } - Not all operators can be stand alone functions. The “()”, “[]”, “->” and the ‘=’ operators must be class methods. A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 46
- When declaring an operator as a class method you only specify the RHS operand. The object is assumed to be the LHS operand. class Complex. Number { public: Complex. Number(float r, float i); Complex. Number operator+(const Complex. Number &n); . . }; Complex. Number: : operator+(const Complex. Numer &n) { float r = Real. Portion + n. Get. Real. Portion(); float i = Image. Portion + n. Get. Image. Portion() ; return Complex. Number(r, i); } A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 47
- You use the same syntax to use a class operator, there is no need to use the member access operator “. ” Main() { Complex. Number n 1(1, 0); Complex. Number n 2(1, 1); Complex. Number n 3; n 3 = n 1 + n 2; } - If the LHS operand is an object of a different class or a primitive type then the operator function must be a stand alone function. A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 48
Operator Overloading - For the “<<” operator the LHS must be an ostream&. - For the “>>” operator the LHS must be an istream&. - For performance reasons the stand alone operator functions for the “<<” and the “>>” operators are made friends of the class. A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 49
class Complex. Number { friend ostream& operator << (ostream& os, const Complex. Number& c); friend istream& operator >> (istream& is, const Complex. Number& c); public: Complex. Number(float r, float i); Complex. Number operator+( const Complex. Number& n); . . private: double Real. Portion; double Image. Portion; }; A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 50
ostream& operator<<(ostream& os, const Complex. Numer& c) { os << “(” << c. Real. Portion << “, ” << c. Image. Portion << “)”; return os; } istream& operator>>(istream& is, const Complex. Numer& c) { is >> c. Real. Portion ; is >> c. Image. Portion; return is; } void main() { Complex. Number c; cout << “Enter the real & imaginary values: ”; cin >> c; cout << c << “ is the number entered. ”; } A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 51
- By having the “<<” and the “>>” operators return a stream object we can string together “<<” and “>>” operator calls. - It’s preferred that operator functions be class methods, unless forced absolutely necessary. - Make nonmember operators friends for efficiency. A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 52
Overloading the [ ] Operator - The “[]” is a binary operator and must be a class method. One should use it to access container elements. - Keep it to the same context as array indexing. The argument should be an index number. class My. String { public: My. String(char Name[]) {strcpy(str, Name); length =strlen(str); } char& operator[](int i) {return str[i]; } int Get. Length() {return length; }; void data(char The. String[]){strcpy(The. String, str); } private: int length; char str[20]; }; A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 53
- What should the [] operator return? In normal array syntax one can change an element. - It should be possible to do this with the String class: void main() { char Stg. Name[20]; My. String s("Heelo"); s[2] = 'l'; // changes 3 rd element from ‘e’ to ‘l’ cout << "The length is: t" << s. Get. Length() << endl; s. data(Stg. Name); cout << "The data is: t" << Stg. Name << endl; } < See: Example 8> A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 54
Overloading Unary Operators - When overloading unary operator, if it is a class method it accepts no arguments. The operator works on the object itself. - If the unary operator is a stand alone function it accepts one argument. - The following implementations of ‘!’ returns TRUE if the String is empty (length of 0), FALSE otherwise. A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 55
// UNARY OPERATOR AS CLASS METHOD class My. String { public: … int operator!() {if (length==0) return true else return false; } }; private: . . . }; OR // UNARY OPERATOR AS FRIEND STAND ALONE FUNCTION int operator!( const My. String& s ) { if (s. length==0) return true else return false; } A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 56
void main() { My. String s; // creates empty string char The. Data[20]; if ( !s ) cout << “String is empty. . . ”; else { s. data(The. Data); cout << The. Data << endl; … } } A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 57
- Sometimes not using an operator makes the code easier to understand. void main() { My. String s; // creates empty string if ( s. Get. Length() == 0 ) cout << “String is empty. . . ”; else cout << s. data() << endl; . . . } A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 58
Overloading ++ and - - Operators “++” and “- -“ can be pre-fixed or post-fixed. The following stand alone and class member operator definitions provide pre-fix syntax. A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 59
// UNARY OPERATOR AS CLASS METHOD class Date { public: …. Date& operator++() { increment_day( 1 ); return *this; }; private: void increment_day( int num. Days ){ // increments the date by one}; int day; int month; int year; }; OR // UNARY OPERATOR AS FRIEND STAND ALONE FUNCTION Date operator++(Date& d ) { d. increment_day(1); return d; } A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 60
- In C++ pre-fix and post-fix are two different operators. - When overloading “++” or “- -“, the compiler differentiates the overloaded operators by an extra dummy argument. - The following are post-fix “++” or “- -“ operators. A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 61
class Date { public: . . . Date& operator++() //pre-fix { increment_day( 1 ); return *this; }; Date& operator++(int dummy) //post-fix { increment_day( 1 ); return *this; }; private: void increment_day( int num. Days ); int day; int month; int year; }; A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 62
OR // STAND ALONE FUNCTIONS Date operator++(Date& d) { d. increment_day(1); return d; } // pre-fix // STAND ALONE FUNCTIONS Date operator++(Date& d, int dummy) // post-fix { d. increment_day(1); return d; } < See: Example 9> A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 63
Inheritance A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 64
Introduction • Inheritance is a form of software reusability in which new class are created from the existing classes. • Software reusability saves time in program and development • It also encourages the reuse of proven or debugged high-quality software. • Reducing problems after the system become functional • When creating a new class, instead of writing completely new class members, the programmers can designate the new class is to inherit the data members previously defined in base class • The new class is called derived class • Some object-oriented databases and OO-programs use the terms super-class and sub-class for base class and derived class, respectively A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 65
Inheritance (2 level) Student Graduate. Student Under. Graduate. Student Account Checking Account A. R. Hadaegh Dr. Ahmad R. Hadaegh Saving. Account California State University San Marcos (CSUSM) Page 66
Inheritance (Multiple level) Community. Member Employee Faculty Administration A. R. Hadaegh Dr. Ahmad R. Hadaegh Student Staff graduate Undergraduate Teacher California State University San Marcos (CSUSM) Page 67
Syntax • To specify that class Faculty is derived from class Employee, class Faculty would be defined as follows: class Faculty: public Employee { …… ; } • This is called public inheritance • All public and protected members of Employee class is inherited by the Faculty class • Friend functions of class Employee are not inherited for the class faculty A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 68
Single/Multiple Inheritance • Single Inheritance: • The derived class only inherits from one base class • Multiple Inheritance: • The derived class inherits from more than one base class • Derived class can also add data members (attributes and/or methods) of its own. A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 69
Public Inheritance • A derived class cannot access the private members of its base class • Allowing this would violate encapsulation of the base class • However, a derived class can access private members of the base only through access functions provided in the base class’s public or protected interfaces. • We explain protected interfaces shortly. A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 70
• Consider the following examples: class Parent { private: int x, y; public: Parent(); void f 1( ); void f 2( ); } A. R. Hadaegh Dr. Ahmad R. Hadaegh class Child: public Parent { private: int z; public: Child(); void f 3( ); } California State University San Marcos (CSUSM) Page 71
• Class parent has two attributes , ‘x’ and ‘y’, and three methods. • Class child has three attributes: one of its own and two inherited from parent class) plus five methods (two of its own and three inherited from the parent class) • Method f 3( ) in the child class can access ‘z’ but it cannot directly access ‘x’ and ‘y’, although ‘x’ and ‘y’ have been inherited from the parent class • If f 3() needs to change the status of ‘x’ and ‘y’, for an object of class child, it has to call f 1() and f 2() to do the job for it. A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 72
• To solve this problem, C++ provides member access called “protected” • If a member has a protected access, it is can be accessed by methods of the derived class, but it is still protected from any outside objects or methods outside of its class hierarchy. • Therefore, C++ provides the protected member access specifier to allow derived classes free access to base class members. • Derived class and their friends functions can access protected members whereas non-friends and non-derived member functions cannot. A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 73
Example of private/protected member This example shows that private members of the parent class cannot be accessed by the methods of the child class Parent { private: int x, y; public: Parent(){}; }; A. R. Hadaegh Dr. Ahmad R. Hadaegh class Child: public Parent { private: int z; public: Child(){}; void f 3( ); }; //--------------void Child: : f 3() { z = 5; x = 10; y = 15 } California State University San Marcos (CSUSM) This gives compile error because x and y are private members Page 74
Example of private/protected member This example shows that protected members of the parent class can be accessed by the methods of the child class but not outside of the class scope class Child: public Parent class Parent { private: { protected: int z; This does not give int x, y; public: any compile error Child(){}; because x and y are public: void f 3( ); protected members Parent(){}; }; }; //--------------void Child: : f 3() { z = 5; x = 10; y = 15 } < See: Examples 10 and 11> A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 75
Public, Private, and Protected Inheritance • Public Inheritance: • Public and protected members of the base class become public and protected members of the derived class, respectively • Protected inheritance: • Public and protected members of the base class become protected members of the derived class • Private inheritance: • Public and protected members of the base class become private members of the derived class • In all of the above forms, private members of the base class can only be accessed through the inherited public or private members (not by the own members) of the derived class. A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 76
Constructor in Inheritance • When an object of the derived class is instantiated, the constructor of the base class is called first. Then the constructor of the derived class is called. • If the base class does not include a constructor, the default constructor of the base class is called • If the base class does include a constructor, the constructor in the derived class can use the base-class initializer (initializing at the function header) to call the default constructor of the base class. A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 77
class Person { private: string name, int age; public: void f 1(); }; class Student: public Person { private: int st. Identifier; public: Student(); } Student: : Student() { st. Identifier = 0; } • In this case, when we create an object of the Student class, the default constructor of the Person class is called. because the Person class has no constructor. <See: Example 12> A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 78
class Person { private: string name, int age; public: Person(); Person(string, int); }; Person: : Person() { age = 0; name = “ ”; } //------------Person: : Person(string n, int a) { age = a; name = n; } //------------- class Student: public Person { private: int st. Identifier; public: Student(int a, string n, int s. Id); } Student: : Student(int a, string n, int s. Id): Person(a, s) { st. Identifier = s. Id; } • In this case, when we create an object of the Student class, the constructor that is determined by the member initialization list of the Student class is invoked <See: Example 13> A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 79
Destructors in Inheritance • Destructor are called in reverse order of the constructors. • First the derived class destructor is called, Then the destructor of the base class is called. <See: Example 14> A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 80
Redefining Base Class Members • A derived class data member with the same name as a base class data member will hide the base class data member in derived class methods. • This does not apply to private base class members, since they are not accessible to the derived class any ways. • You can use the scope resolution operator “: : ” to access base class members which are overridden by the derived class. • Derived class methods with the exact same signature as a base class method override the base class method when accessed via a derived class object (“regular” variable, pointer or reference). A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 81
class Person { public: string name; void f 1( ) {cout << "This is f 1( ) in Person"<< endl; } }; class Employee: public Person { public: string name; void f 1( ) {cout << "This is f 1( ) in Employee"<< endl; } }; A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 82
void main () { Person p; Employee e; e. name = "Bob"; e. f 1( ); e. Person: : name = "Jim"; e. Person: : f 1(); } // sets the specialized name to Bob // calls the specialized name // sets the inherited name to Jim // calls the inherited method f 1() The output is This is f 1( ) in Employee This is f 1( ) in Person <See: Example 15> A. R. Hadaegh Dr. Ahmad R. Hadaegh California State University San Marcos (CSUSM) Page 83
- Slides: 83