15.5 OVERLOADING OPERATORS FOR DERIVED CLASSES IN C


15.5 OVERLOADING OPERATORS FOR DERIVED CLASSES IN C++

Operator overloading in C++ was discussed earlier in Chapter 12. The question that we will address in this section is whether anything different needs to be done in the overload definition of an operator for a derived class if the same operator has been overloaded for the base class. As you will see in this section, if you want the derived-class overload definition to use the base-class overload definition for doing part of the work, then you may have to use what is known as upcasting.

As an example of operator overloading for derived classes, in this section we will consider the specific case of overloading the output operator ‘<<’ for a derived class. The same discussion extends to other operator overloadings. Let's consider the three–class hierarchy of Figure 15.3. For each class we will define a constructor, a copy constructor, and a copy assignment operator and will declare the function operator<< to be a friend. To appreciate this example, focus on the global overload definition of the output operator ‘<<’ and see how this definition changes when we go from the base-class Person to the derived-class Employee and then to the further derived-class Manager.

click to expand
Figure 15.3

In the program shown below, for the base-class Person, the overload definition for the output operator in line (D) is

      ostream& operator<<( ostream& os, const Person& p ) {          os << p.name;          return os;      } 

which is straightforward and in accord with such examples shown earlier in Chapter 12. However, for the derived-class Employee, the overload definition as shown in line (E) is

      ostream& operator<<( ostream& os, const Employee& e ) {          Person* ptr = &e;                                                          //(A)          os << *ptr;                                                                //(B)          os << " " << e.department << " " << e.salary                               //(C)          return os;      } 

Note how in line (A) above, we first upcast the Employee object and obtain a pointer of type Person pointing to the same object. When the output operator is invoked in line (B) on the resulting Person object, it will print out the Person slice of the Employee object. We then output the rest of the Employee object in line (C). In the program below, as shown in line (F), we do the same thing in the Manager class vis-à-vis its base-class Employee.

 
//DerivedOverloadOp.cc #include <iostream> #include <string> using namespace std; /////////////////////////// class Person /////////////////////////// class Person { string name; public: Person( string nom ) : name( nom ) {} Person( const Person& p ) : name( p.name ) {} Person& operator=( const Person& p ) { if ( this != &p ) name = p.name; return *this; } virtual Person() {} friend ostream& operator<<( ostream& os, const Person& p ); }; //overload << for base class Person: ostream& operator<<( ostream& os, const Person& p ) { //(D) os << p.name; return os; } ////////////////////////// class Employee ////////////////////////// class Employee: public Person { string department; double salary; public: Employee( string name, string dept, double s ) : Person( name ), department( dept ), salary( s ) {} Employee( const Employee& e ) { : Person( e ), department( e.department ), salary( e.salary ) {} Employee& operator=( const Employee& e ) { if ( this != &e) { Person::operator=( e ); department = e.department; salary = e.salary; } return *this; } ~Employee() {} friend ostream& operator<<( ostream& os, const Employee& p ); }; //overload << for derived class Employee: ostream& operator<<( ostream& os, const Employee& e ) { //(E) const Person* ptr = &e; //upcast os << *ptr; os << " " << e.department << " " << e.salary; return os; } /////////////////////////// class Manager /////////////////////////// class Manager: public Employee { string title; public: Manager( string name, string dept, double salary, string atitle ) : Employee( name, dept, salary ), title( atitle ) {} Manager( const Manager& m ) : Employee( m ), title( m.title ) {} Manager& operator=( const Manager& m ){ if ( this != &m ) { Employee::operator=( m ); title = m.title; } return *this; } ~Manager() {} friend ostream& operator<<( ostream& os, const Manager& m ); }; //overload << for derived class Manager: ostream& operator<<( ostream& os, const Manager& m ) { //(F) const Employee* ptr = &m; //upcast os << *ptr; os << " " << m.title; return os; } /////////////////////////////// main /////////////////////////////// int main() { Manager m1( "Zahpod", "assembly", 100, "director" ) Manager m2( m1 ); // invokes copy construct cout << m2 << endl; // Zaphod assembly 100 director Manager m3( "Trillion", "sales", 200, "vice_pres" ); m2 = m3; // invokes assignment oper cout << m2 << endl; // Trillion sales 200 vice_pres return 0; }




Programming With Objects[c] A Comparative Presentation of Object-Oriented Programming With C++ and Java
Programming with Objects: A Comparative Presentation of Object Oriented Programming with C++ and Java
ISBN: 0471268526
EAN: 2147483647
Year: 2005
Pages: 273
Authors: Avinash Kak

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net