150 likes | 255 Views
Inheritance mechanism. class Person { public: void f( void ){ cout < ”Person<br>”; } }; class Employee { public: void f( void ){ cout ”Employee<br>”; } } Person p1; p1.f(); Person *p2 = new Employee; p2->f(); Employee p3; void g( Person p ){ p.f(); } g( p3 );. What is printed?.
E N D
Inheritance mechanism class Person { public: void f( void ){ cout < ”Person\n”; } }; class Employee { public: void f( void ){ cout ”Employee\n”; } } Person p1; p1.f(); Person *p2 = new Employee; p2->f(); Employee p3; void g( Person p ){ p.f(); } g( p3 ); What is printed? C++ by default uses the methods according to the type is knows, not of the actual object (static binding).
Printing a person class Person { public: Person (const char * name); ~Person (void); // I/O friend. friend ostream & operator<<( ostream & os, const Person & p ); protected: char * name; }; class Student : public Person { public: Student (const char * n, const float * m, int nr); ~Student (void); // I/O friend. friend ostream & operator<<( ostream & os, const Student & s ); private: int nrMarks; float * marks; };
Printing a person int main (void){ Person m ("Marten Wensink"); float cijfers [5] = {6.4f, 7.5f, 4.2f}; Student s ("D.E.Student", cijfers, 3); cout << m << '\n' << s << '\n' << endl; cout << "********* Testing references. ********\n"; Person & r0 = m; Person & r1 = s; // Display using references: cout << r0 << endl; cout << r1 << endl << endl; cout << "********* Testing pointers. **********\n"; Person * p[2]; p[0] = new Person ("Marten Wensink"); p[1] = new Student ("D.E.Student", cijfers, 3); // Display using pointers: for (int i = 0; i < 2; i++){ cout << *p[i] << endl; } cout << endl; cout << "*** Testing destructors for array. ***\n"; for (i = 0; i < 2; i++){ delete p[i]; cout << endl; } cout << "Finalising program...\n"; return 0; } Person: Marten Wensink Student: D.E.Student Cijfers: 6.4 7.5 4.2 ************ Testing references. *********** Person: Marten Wensink Person: D.E.Student ************* Testing pointers. ************ Person: Marten Wensink Person: D.E.Student ****** Testing destructors for array. ****** Calling destructor for Person. Calling destructor for Person. Finalising program... Calling destructor for Student. Calling destructor for Person. Calling destructor for Person. 3 destructors called. For which objects?
Dynamic binding • At run time, check to which class the actual object belongs, and use the method from that actual class. • Does what you expect. • Is somewhat slower than the default static binding. class Person { public: Person (const char * name); virtual ~Person (void); friend ostream & operator<<( ostream & os, const Person & p ); protected: char * name; }; This friendly operator<< is not a member function, so it can not be virtual
Delegate printing to a member function class Person { public: // Destructor (should always be virtual !!). virtual ~Person (void); // I/O friend. friend ostream & operator<< (ostream & os, const Person & p){ p.printInfo(os); return os; } private: // Private virtual function. virtual void printInfo (ostream & os) const; }; • ”virtual-ness” is inherited: • No need to re-specify it in a derived class • You can’t even do that: it must be mentioned in the highest class!
Abstract classes You can postpone the body of a member function by specifying it as =0 : class Vehicle { public: . . . private: // Pure virtual operation virtual void printInfo (ostream & os) const = 0; }; Such a function is called pure virtual. A class with at least one such function is called abstract. C++ has no interface classes, but a class with all functions pure virtual has the same effect.
Abstract classes You can postpone the body of a member function by specifying it as =0 : class Vehicle { . . . private: // Pure virtual operation virtual void printInfo (ostream & os) const = 0; }; Such a function is called pure virtual. A class with at least one such function is called abstract. An abstract class can not be instantiated. C++ has no interface classes, but a class with all functions pure virtual has the same effect.
Vehicles class hierargy Note: operator=, copy constructor, etc. not show!
Vehicle class Vehicle { public: // Virtual destructor virtual ~Vehicle (void) { } // I/O-friend friend ostream & operator<<( ostream & os, const Vehicle & v ){ v.printInfo (os); return os; } private: // Pure virtual operation virtual void printInfo (ostream & os) const = 0; }; Vehicle is virtual: it is an abstract entity, you can’t buy just a vehicle.
Bike class Bike : public Vehicle { // No extra operations. // No data. }; Bike does not define the printInfo, so it is also virtual.
RaceBike class RaceBike : public Bike { public: // Constructor. RaceBike (int n) : numGears (n) { } protected: int numGears; private: void printInfo (ostream & os) const; }; void RaceBike::printInfo ( ostream & os ) const { os << "A race bike with " << numGears << " gears"; } printInfo is implemented, so RaceBike is a concrete claass.
MotorVehicle class MotorVehicle : public Vehicle { public: MotorVehicle (const char * num ){ regNum = new string (num); } ~MotorVehicle (void){ cout << "Destruction of " << *regNum << endl; delete regNum; } const string & number (void) const{ return *regNum; } protected: string * regNum; private: void printInfo (ostream & os) const; }; printInfo is implemented, so MotorVehicle is a concrete class. void MotorVehicle::printInfo (ostream & os) const { os << "A motor vehicle with reg.no: " << number(); }
PrivateCar class PrivateCar : public MotorVehicle { public: // Constructor. PrivateCar( const char * num, int n ): MotorVehicle (num), numSeats (n) {} protected: int numSeats; private: void printInfo (ostream & os) const; }; printInfo is implemented, so PrivateCar is a concrete class. (and if it was not?) void PrivateCar::printInfo (ostream & os) const { os << "A private car with reg.no: " << number() << " and " << numSeats << " seats"; } Bad practice. How should this be done?
Printing vehicles int main( void ){ MotorVehicle m ("MW-100"); cout << m << endl; Vehicle * pM = new MotorVehicle ("MW-101"); cout << *pM << endl; Vehicle & vr = m; cout << vr << endl << endl; PrivateCar c ("MW-200", 4); cout << c << endl; Vehicle * pC = new PrivateCar ("MW-201", 5); cout << *pC << endl; MotorVehicle * pPC = new PrivateCar ("MW-202", 6); cout << *pPC << endl << endl; RaceBike rb (10); cout << rb << endl; Bike * pRB = new RaceBike (14); cout << *pRB << endl; Vehicle * pV = new RaceBike (16); cout << *pV << endl; cout << "\n********** Deleting objects. *******\n"; delete pM; delete pC; delete pPC; delete pRB; delete pV; cout << "\n******** Finalising program. *******\n"; } A motor vehicle with reg.no: MW-100 A motor vehicle with reg.no: MW-101 A motor vehicle with reg.no: MW-100 A private car with reg.no MW-200 and 4 seats A private car with reg.no MW-201 and 5 seats A private car with reg.no MW-202 and 6 seats A race bike with 10 gears A race bike with 14 gears A race bike with 16 gears ************* Deleting objects. ************ Destruction of MW-101 Destruction of MW-201 Destruction of MW-202 ************ Finalising program. *********** Destruction of MW-200 Destruction of MW-100 .