100 likes | 199 Views
Advanced Topics on Inheritance. M ultiple inheritance allows a derived class to inherit from more than one direct base class class Bear: public ZooAnimal {/*...*/}; class Panda: public Bear, public Endangered { /*...*/ };
E N D
Advanced Topics on Inheritance • Multiple inheritance allows a derived class to inherit from more than one direct base class class Bear: public ZooAnimal {/*...*/}; class Panda: public Bear, public Endangered {/*...*/}; • Virtual Inheritance allows the derived to class to share the base class, as a single virtual base class • Regardless how often a base class shows up on different inheritance paths, only one base class will be included
class A { public: A(int num): aInt(num) { cout << "A::constructor"<<endl;;} ~A() { cout <<"A::destructor"<<endl;} protected: int aInt; }; class B: public A { public: B(int numa, int numb) : A(numa), bInt(numb) { cout << "B::constructor"<<endl;} ~B() { cout << "B::destructor"<<endl;} protected: int bInt; }; int main (int, char * []){ B b(2, 3); return 0; } Output: A::constructor B::constructor B::destructor A::destructor Order of execution constructors: base class first then derived class destructors: reverse of constructors Single Inheritance A B
// A and B are as declared // in the previous slide class C: public B { public: C(int numa, int numb, string s ) : B(numa, numb), cStr(s) { cout << "C::constructor"<<endl;} ~C() { cout << "C::destructor"<<endl;} protected: string cStr; }; int main (int, char * []) { C c(4, 7, "hello"); return 0; } Output: A::constructor B::constructor C::constructor C::destructor B::destructor A::destructor Single Inheritance, continued A B C
class X { public: X(): xChar('D') {cout << "X::default constructor"<<endl;;} X(char c): xChar(c) {cout << "X::constructor"<<endl;;} ~X() { cout << "X::destructor"<<endl;} protected: char xChar; }; class Y { public: Y(char c): yChar(c) { cout << "Y::constructor"<<endl;;} ~Y() {cout << "Y::destructor"<<endl;} protected: char yChar; }; class Z : public X, public Y { public: Z(char xC,char yC, int num) : X(xC), Y(yC), zInt(num) { cout << "Z::constructor"<<endl;} ~Z() { cout << "Z::destructor"<<endl;} protected: int zInt; }; int main (int, char *[])) { Z zObj('z', 'b', 8); return 0; } Output: X::constructor Y::constructor Z::constructor Z::destructor Y::destructor X::destructor Multiple Inheritance Y X Z
class MI: public C, public Z { public: MI(int numa, int numb, string s, char xC, char yC, int numZ ) : C(numa, numb, s), Z(xC, yC, numZ) {cout << "MI::constructor"<<endl;} ~MI() {cout << "MI::destructor"<<endl;} protected: string cStr; }; int main (int, char * []) { MI mi(2,4,"eve", 'r', 's', 26); return 0; } Output: A::constructor B::constructor C::constructor X::constructor Y::constructor Z::constructor MI::constructor MI::destructor Z::destructor Y::destructor X::destructor C::destructor B::destructor A::destructor Multiple Inheritance, continued A Y X B Z C MI
// X and Y as declared previously class R : public X, public Y { public: R(char xC, char yC, int numx): Y(yC), X(xC), rInt(numx) {cout << "R::constructor" << endl;} ~R() { cout << "R::destructor" <<endl;} protected: int rInt; }; class S : public Y, public X { public: S(char yC, int numx): Y(yC), sInt(numx) {cout << "S::constructor"<<endl;} ~S() {cout << "S::destructor"<<endl;} protected: int sInt; }; int main (int, char * []) { Rr ('x', 'y', 8); return 0; } Output: X::constructor Y::constructor R::constructor R::destructor Y::destructor X::destructor int main (int, char * []) { S s('y', 10); return 0; } Output: Y::constructor X::default constructor S::constructor S::destructor X::destructor Y::destructor All Base Class Constructors are Called
// Based on LLM Ch. 18.3 and // today’s studio exercises Bear * bear_ptr = new Panda ("bao_bao"); bear_ptr ->print(); // ok bear_ptr ->toes(); // ok bear_ptr ->cuddle(); // not ok bear_ptr ->growl(); // not ok delete bear_ptr; // ok Endangered * endangered_ptr = new Grizzly; endangered_ptr->print(); // ok endangered_ptr->toes(); // not ok endangered_ptr ->cuddle();// not ok endangered_ptr ->growl(); // not ok delete endangered_ptr; // ok Base Pointer/Reference Type Restricts Interface
When a class has multiple base classes, a derived class can inherit a member with the same name from two or more base classes Unqualified uses of that name are ambiguous // Loosely based on LLM Ch. 18.3 double Gryphon:max_weight() const { return std::max (Eagle::max_weight_, // scoping necessary Lion::max_weight_); // scoping necessary }; This in turn motivates the use of virtual base classes // Single Animal instance shared by Eagle and Lion parts of Gryphon class Eagle : virtual public Animal {/*...*/}; class Lion : virtual public Animal {/*...*/}; class Gryphon : public Eagle, public Lion {/*...*/}; Member Inheritance from Multiple Base Classes
Still Polymorphic Can convert between uses as Derived vs. Base Members of virtual Base class normally can be uniquely identified base class is instantiatedonly once if the variable is in both base and derived class, then derived class has higher precedence If the member is in 2 derived classes, then it is still ambiguous move members up to avoid that, e.g., Animal::max_weight_ The most derived class controls the initialization of the shared virtual base class More About Virtual Base Classes
Constructors All virtual base classes up each branch of the inheritance lattice, according to order in which immediate base classes were declared Non-virtual base classes up each branch of the inheritance lattice, according to order in which immediate base classes were declared Most derived class last Destructors (in reverse order of constructors) Most derived class first Then each non-virtual base class, moving up lattice Then each virtual base class, moving up lattice Virtual Base Class Constructor/Destructor Order