Presentation is loading. Please wait.

Presentation is loading. Please wait.

1 159.234LECTURE 17 159.234 LECTURE 17 More on Inheritance, Virtual Inheritance, & Virtual Destructors, 17.

Similar presentations


Presentation on theme: "1 159.234LECTURE 17 159.234 LECTURE 17 More on Inheritance, Virtual Inheritance, & Virtual Destructors, 17."— Presentation transcript:

1 1 159.234LECTURE 17 159.234 LECTURE 17 More on Inheritance, Virtual Inheritance, & Virtual Destructors, 17

2 2 More on Inheritance Parent Constructors and Destructors class X { public: X() { cout << "X::X() Ctor executing. " << endl; } ~X() { cout << "X::~X() Dtor executing." << endl;} }; class Y : public X { public: Y() { cout << "Y::Y() Ctor executing. " << endl; } ~Y() { cout << "Y::~Y() Dtor executing." << endl;} }; Let’s consider the following inheritance hierarchy: 1 Parent Ctor and Dtor.cpp

3 3 More on Inheritance Parent Constructors and Destructors class Z : public Y { public: Z(int n) { cout << "Z::Z(int) Ctor executing. " << endl; } ~Z() { cout << "Z::~Z() Dtor executing." << endl; }; When Z is declared, its ctor Z::Z(int) is called. Before executing, it calls the Y::Y() ctor which immediately calls the X::X() ctor. After X::X() ctor finishes, control is returned to Y::Y(). As soon as Y::Y() finishes, Z::Z() gains control and finishes last. Parent Ctor and Dtor.cpp

4 4 More on Inheritance Parent Constructors and Destructors Parent default constructors execute in top-down order. X::X() Ctor executing. Y::Y() Ctor executing. Z::Z(int) Ctor executing. Z::~Z() Dtor executing. Y::~Y() Dtor executing. X::~X() Dtor executing. * Parent Ctor and Dtor.cpp

5 5 More on Inheritance Parent Constructors and Destructors 2 class Person { public: Person(const char* s) { cout << "Person::Person() ctor." << endl; name = new char[strlen(s)+1]; strcpy(name,s); } ~Person(){ delete [] name; cout << "Person::~Person() Dtor." << endl; } protected: char *name; }; Let’s consider the following inheritance hierarchy: Parent Ctor and Dtor - Dtor calls.cpp

6 6 More on Inheritance Parent Constructors and Destructors class Student: public Person { public: Student(const char* s, const char* m) : Person(s) { cout << "Student::Student() ctor." << endl; major = new char[strlen(m)+1]; strcpy(major,m); } ~Student(){ delete [] major; cout << "Student::~Student() dtor." << endl; } protected: char *major; }; Class derived from Person Parent Ctor and Dtor - Dtor calls.cpp

7 7 More on Inheritance Parent Constructors and Destructors int main() { Person x("Scratchy"); { Student y("Itchy","Biology") ; } return 0; } The main function: Parent Ctor and Dtor - Dtor calls.cpp

8 8 More on Inheritance Parent Constructors and Destructors Person::Person() ctor. Student::Student() ctor. Student::~Student() Dtor. Person::~Person() Dtor. When x is instantiated, the Person ctor is called, allocating 9 bytes of memory to store the string “Scratchy”. Next, y instantiates, first calling the Person ctor, which allocates 6 bytes to store the string “Itchy” and then allocating 8 more bytes to store the String “Biology”. Parent Ctor and Dtor - Dtor calls.cpp int main() { Person x("Scratchy"); { Student y("Itchy","Biology") ; } return 0; }

9 9 More on Inheritance Parent destructors execute in a bottom-up order. * Person::Person() ctor. Student::Student() ctor. Student::~Student() Dtor. Person::~Person() Dtor. When the scope of y terminates, y’s dtor deallocates the 8 bytes used for “Biology”and then calls the Person dtor which deallocates the 6 bytes used for “Itchy”. Finally, the Person dtor is called to Destroy x, deallocating the 9 bytes used for “Scratchy” Parent Ctor and Dtor - Dtor calls.cpp int main() { Person x("Scratchy"); { Student y("Itchy","Biology") ; } return 0; }

10 10 More on Inheritance Parent Constructors and Destructors In an inheritance hierarchy, each constructor invokes its parent constructor before executing itself, and each destructor invokes its parent destructor after executing itself. 17 Summary:

11 11 More on Inheritance Virtual Destructors Virtual functions are by functions that have the same ‘signature’ and are defined in derived classes. Virtual functions are overridden by functions that have the same ‘signature’ and are defined in derived classes. 17 Since the names of constructors and destructors are unique for each class, it leads us to think that they cannot be declared virtual. That is only true for constructors. Constructors are always unique for each class. On the other hand, destructors could be made virtual.

12 12 More on Inheritance Memory Leak Consider the following class named X: 17 class X { public: X() { p = new int[2]; cout << "X(). "; } ~X() { delete [] p; cout << "~X()." << endl;} private: int *p; }; Virtual Destructor - Memory Leak.cpp

13 13 Virtual Destructor Memory Leak And another class named Y, derived from X: 17 class Y : public X { public: Y() { q = new int[1023]; cout << "Y() : Y::q = " << q << ". "; } ~Y() { delete [] q; cout << "~Y(). ";} private: int *q; }; Virtual Destructor - Memory Leak.cpp

14 14 Virtual Destructor Memory Leak Each iteration creates a new instance of Y 17 int main() { for(int i=0; i < 8; ++i) { X *r = new Y; delete r; } return 0; } Where is the memory leak here? This loop would invoke the base class’s constructor, as well as Y’s constructor, Allocating 4100 bytes (4 bytes for each int) Note: 1023*4 + 2*4 = 4100 bytes Virtual Destructor - Memory Leak.cpp

15 15 Virtual Destructor Memory Leak Let’s see the program in action. 17 int main() { for(int i=0; i < 8; ++i) { X *r = new Y; delete r; } return 0; } r is declared to be a pointer to X objects. Only the X destructor is invoked! It deallocates only 8 bytes, and so 4092 bytes are lost! Virtual Destructor - Memory Leak.cpp

16 16 X(). Y() : Y::q = 0x3d37c8. ~X(). X(). Y() : Y::q = 0x3d47d0. ~X(). X(). Y() : Y::q = 0x3d57d8. ~X(). X(). Y() : Y::q = 0x3d67e0. ~X(). X(). Y() : Y::q = 0x3d77e8. ~X(). X(). Y() : Y::q = 0x3d87f0. ~X(). X(). Y() : Y::q = 0x3d97f8. ~X(). X(). Y() : Y::q = 0x3da800. ~X(). Virtual Destructor Program Output 17 Only the X destructor is invoked! So, how can we invoke the Y destructor? Virtual Destructor - Memory Leak.cpp Everything but dynamically allocated objects (that is, local objects, temporary objects, member objects, static objects, and array elements) are destructed in the reverse order of construction: first constructed is last destructed.

17 17 Virtual Destructor To plug this memory leak, 17 Change the base class’s destructor into a virtual function. class X { public: X() { p = new int[2]; cout << "X(). "; } virtual ~X(){ delete [] p; cout << "~X()." << endl; } private: int *p; }; Rule of thumb: dynamic binding Declare the base destructor virtual whenever your class hierarchy uses dynamic binding! Virtual Destructor - Memory Leak Resolved.cpp

18 18 Virtual Destructor Program Output 17 Each iteration of the loop calls both destructors, restoring all memory that was allocated by the new operator. X(). Y() : Y::q = 0x3d37c8. ~Y(). ~X(). Virtual Destructor - Memory Leak Resolved.cpp

19 19 More on Inheritance “Dreaded Diamond” of Class Inheritance 17 Base Derived1Derived2 Join Just something to be aware of… Base is inherited twice, which means that any data members declared in Base will appear twice within a Join object. This can create ambiguities: which data derived from Base would you want to change? Also, there’s an ambiguity In converting from Join* to Base*, or from Join& to Base&.

20 20 More on Inheritance “Dreaded Diamond” of Class Inheritance 17 Base Derived1Derived2 Join class Base{ public: protected: int data; }; class Derived1 : public Base {..} class Derived2 : public Base {..} class Join : public Derived1, public Derived2{ public: void method(){ data = 1; } int main() { Join* j = new Join(); Base* b = j; return 0; } ambiguous DreadedDiamond.cpp

21 21 More on Inheritance “Dreaded Diamond” of Class Inheritance 17 Base Derived1Derived2 Join C++ lets us resolve the ambiguities using full qualification of data (e.g. Derived2::data = 1). Likewise, you could convert from Join* to Derived1* and then to Base*. That is not the best solution however.

22 22 More on Inheritance “Dreaded Diamond” of Class Inheritance 17 Base Derived1Derived2 Join The best solution is to tell the compiler that there should be only one copy of the data member(s) derived from Base that should appear within a Join object. virtual keyword inheritance part Use the virtual keyword in the inheritance part of the classes that derive directly from the top of the diamond. virtualvirtual

23 23 More on Inheritance “Dreaded Diamond” of Class Inheritance 17 class Base{ public: protected: int data; }; virtual class Derived1 : public virtual Base {..} virtual class Derived2 : public virtual Base {..} class Join : public Derived1, public Derived2{ public: void method(){ data = 1; } int main() { Join* j=new Join(); Base* b=j; return 0; } good! Therefore, an instance of Join will have only a single Base subobject. This eliminates ambiguities. DreadedDiamond.cpp

24 24 More on Inheritance “Delegate to a sister class” via virtual inheritance 17 class Base{ public: virtual void foo() = 0; virtual void bar() = 0; }; class Derived1 : public virtual Base{ public: virtual void foo(); }; class Derived2: public virtual Base{ public: virtual void bar() { cout << "void Derived2::bar()" << endl;} }; class Join: public Derived1, public Derived2{}; int main() { Join* p1 = new Join(); Derived1* p2 = p1; Base* p3 = p1; p1->foo(); p2->foo(); p3->foo(); return 0; } ? How does Derived1 know anything about bar()? bar(); void Derived1::foo() { bar(); } Delegate to a sister class.cpp

25 25 More on Inheritance “Delegate to a sister class” via virtual inheritance 17 Believe it or not, when Derived1::foo() calls this->bar(), it ends up calling Derived2::bar(). A class Derived1 knows nothing about will supply the override of a virtual function invoked by Derived1::foo(). cross delegation This ‘cross delegation’ can be a powerful technique for customizing the behaviour of polymorphic classes. Delegate to a sister class.cpp

26 26 Other Examples Shapes.cpp * 17 For more examples, see the following codes abstract.cpp, virtual.cpp, virt_sel.cpp, vir_err.cpp PassingCar.cpp All downloadable from our site! Delegate to a sister class.cpp


Download ppt "1 159.234LECTURE 17 159.234 LECTURE 17 More on Inheritance, Virtual Inheritance, & Virtual Destructors, 17."

Similar presentations


Ads by Google