Inheritance mechanism
description
Transcript of Inheritance mechanism
W 6 L 1 sh 1
Lesson Subject Book
Week 4 lesson 1 Class, copy-constructor H7.1-7.4; p197 – 226
Week 4 lesson 2 Operators 1 H8.1-8.4.2; p237 – 254
Week 5 lesson 1 Operators 2 H8.4.3-8.5; p254 – 266
Week 5 lesson 2 Inheritance H9.1-9.3; p269 – 286
Week 6 lesson 1 Virtual methods H9.5-9.8; p301 – 322 (excluding 9.6)
Week 6 lesson 2 Exceptions H10.1-10.2; p329 – 343
Inheritance mechanism
C++ by default uses the methods according to the type is knows, not of the actual object (static binding).
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?
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 WensinkStudent: D.E.StudentCijfers: 6.4 7.5 4.2 ************ Testing references. ***********Person: Marten WensinkPerson: D.E.Student ************* Testing pointers. ************Person: Marten WensinkPerson: 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
class Vehicle {public: . . . private: // Pure virtual operation virtual void printInfo (ostream & os) const = 0;};
C++ has no interface classes, but a class with all functions pure virtual has the same effect.
Such a function is called pure virtual.A class with at least one such function is called abstract.
You can postpone the body of a member function by specifying it as =0 :
Abstract classes
class Vehicle { . . .private: // Pure virtual operation virtual void printInfo (ostream & os) const = 0;};
C++ has no interface classes, but a class with all functions pure virtual has the same effect.
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.
You can postpone the body of a member function by specifying it as =0 :
Vehicles class hierargy
Vehicle
<<virtual>> ~Vehicle()<<abstract>> printInfo()operator<<()
<<abstract>>
Bike<<abstract>>
RaceBike
numGears : int
printInfo(os : ostream &)
MotorVehicle
regNum : string *
~MotorVehicle()number() : const string &printInfo(os : ostream &)
PrivateCar
numSeats : int
printInfo(os : ostream &)
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.
Vehicle
<<virtual>> ~Vehicle()<<abstract>> printInfo()operator<<()
<<abstract>>
Bike<<abstract>>
RaceBike
numGears : int
printInfo(os : ostream &)
MotorVehicle
regNum : string *
~MotorVehicle()number() : const string &printInfo(os : ostream &)
PrivateCar
numSeats : int
printInfo(os : ostream &)
Bike
class Bike : public Vehicle { // No extra operations. // No data.};
Bike does not define the printInfo, so it is also virtual.
Vehicle
<<virtual>> ~Vehicle()<<abstract>> printInfo()operator<<()
<<abstract>>
Bike<<abstract>>
RaceBike
numGears : int
printInfo(os : ostream &)
MotorVehicle
regNum : string *
~MotorVehicle()number() : const string &printInfo(os : ostream &)
PrivateCar
numSeats : int
printInfo(os : ostream &)
RaceBike
class RaceBike : public Bike {public: // Constructor. RaceBike (int n) : numGears (n) { } protected: int numGears;
private: void printInfo (ostream & os) const;};
printInfo is implemented, so RaceBike is a concrete claass.
Vehicle
<<virtual>> ~Vehicle()<<abstract>> printInfo()operator<<()
<<abstract>>
Bike<<abstract>>
RaceBike
numGears : int
printInfo(os : ostream &)
MotorVehicle
regNum : string *
~MotorVehicle()number() : const string &printInfo(os : ostream &)
PrivateCar
numSeats : int
printInfo(os : ostream &)
void RaceBike::printInfo ( ostream & os ) const { os << "A race bike with " << numGears << " gears";}
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.
Vehicle
<<virtual>> ~Vehicle()<<abstract>> printInfo()operator<<()
<<abstract>>
Bike<<abstract>>
RaceBike
numGears : int
printInfo(os : ostream &)
MotorVehicle
regNum : string *
~MotorVehicle()number() : const string &printInfo(os : ostream &)
PrivateCar
numSeats : int
printInfo(os : ostream &)
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?)
Vehicle
<<virtual>> ~Vehicle()<<abstract>> printInfo()operator<<()
<<abstract>>
Bike<<abstract>>
RaceBike
numGears : int
printInfo(os : ostream &)
MotorVehicle
regNum : string *
~MotorVehicle()number() : const string &printInfo(os : ostream &)
PrivateCar
numSeats : int
printInfo(os : ostream &)
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-100A motor vehicle with reg.no: MW-101A motor vehicle with reg.no: MW-100 A private car with reg.no MW-200 and 4 seatsA private car with reg.no MW-201 and 5 seatsA private car with reg.no MW-202 and 6 seats A race bike with 10 gearsA race bike with 14 gearsA race bike with 16 gears ************* Deleting objects. ************Destruction of MW-101Destruction of MW-201Destruction of MW-202 ************ Finalising program. ***********Destruction of MW-200Destruction of MW-100.