Week 8 C++ Inheritance and MultiInheritance
_______________ occur when a program attempts to access memory not allowed. This is often caused by improper usage of pointers in the source code, dereferencing a null pointer as shown in the example below.
Segmentation fault
In general, it is not allowed to call the grandparent's constructor directly, it has to be called through parent class. It is allowed only when ________________ is used.
'virtual' keyword
If you want to call .area() from ppoly1 and ppoly2 pointers what do you do? class Polygon { protected: int width, height; public: void set_values (int a, int b) { width=a; height=b; } }; class Rectangle: public Polygon { public: int area() { return width*height; } }; class Triangle: public Polygon { public: int area() { return width*height/2; } }; int main () { Rectangle rect; Triangle trgl; Polygon * ppoly1 = ▭ Polygon * ppoly2 = &trgl; ppoly1->set_values (4,5); ppoly2->set_values (4,5); cout << rect.area() << '\n'; cout << trgl.area() << '\n'; return 0; }
1. add a virtual method to the base class class Polygon { protected: int width, height; public: void set_values (int a, int b) { width=a; height=b; } virtual int area(){ return 0; }; }; class Rectangle: public Polygon { public: int area() { return width*height; } }; class Triangle: public Polygon { public: int area() { return width*height/2; } }; int main () { Rectangle rect; Triangle trgl; Polygon * ppoly1 = ▭ Polygon * ppoly2 = &trgl; ppoly1->set_values (4,5); ppoly2->set_values (4,5); cout << ppoly1.area() << '\n'; cout << ppoly2.area() << '\n'; return 0; }
Fix this: class Person { public: Person(int x) { ... } Person() { ... } }; class Faculty : virtual public Person { public: Faculty(int x):Person(x) { .... } }; class Student : public Person { public: Student(int x):Person(x) { .... } }; class TA : public Faculty, public Student { public: TA(int x):Student(x), Faculty(x) { ..... } };
1. add virtual when Student inherits from Person 2. add the granddparent constructor Person() to end of TA constructor inheritance. class Person { public: Person(int x) { ... } Person() { ... } }; class Faculty : virtual public Person { public: Faculty(int x):Person(x) { .... } }; class Student : virtual public Person { public: Student(int x):Person(x) { .... } }; class TA : public Faculty, public Student { public: TA(int x):Student(x), Faculty(x), Person(x) { ..... } };
What will be the order of operations when an object of c is created? class C: public B, public A // Note the order { public: C() { cout << "C's constructor called" << endl; } };
B's constructor will be called followed by A's C's
Rewrite to make this use dynamic memory on the Heap Base *bp; Derived de; bp = &de; bp->show();
Base *bp = new Derived(); bp->show(); delete bp;
Why would you use rect.area() instead of ppoly1.area() below? class Polygon { protected: int width, height; public: void set_values (int a, int b) { width=a; height=b; } }; class Rectangle: public Polygon { public: int area() { return width*height; } }; class Triangle: public Polygon { public: int area() { return width*height/2; } }; int main () { Rectangle rect; Triangle trgl; Polygon * ppoly1 = ▭ Polygon * ppoly2 = &trgl; ppoly1->set_values (4,5); ppoly2->set_values (4,5); cout << rect.area() << '\n'; cout << trgl.area() << '\n'; return 0; }
Because the type of ppoly1 and ppoly2 is pointer to Polygon (and not pointer to Rectangle nor pointer to Triangle), only the members inherited from Polygon can be accessed, and not those of the derived classes Rectangle and Triangle. That is why the program accesses the .area() of both objects using rect and trgl.
class D: public B, public C { public: D(int i): B(), C(), A(i){ ... } };
D is inheriting from B and C, which have the same super class A. A is called in the constructor to pass in parameters to the superclass.
Do you need to delete this pointer? base *bptr; derived d; bptr = &d;
No there is no new keyword so it is not using dynamic memory and there will not be any memory leaks.
class Base { int x, y; }; class Derived : public Base { int z, w; }; int main() { Derived d; Base b = d; }
Object Slicing will occur. The z and w of d are sliced off, since the derived class is assigned to a base class.
When do you need to delete pointer?
Only when you use the new keyword
Call sing on shy in main: class Diva { public: virtual void sing() { cout << "Diva sing\n"; } virtual void hum() { cout << "Diva hum\n"; } }; class Shy: public Diva { public: void hum() { cout << "Shy hum\n"; } private: void sing() { cout << "Shy sing\n"; } // suppressed };
Shy s; Diva * dPtr = &s; dPtr->shy();
class Derived: public Base { public: Derived(int i, int j):Base(i) { year = j; } ... private: int year; }
The Derived class inherits from Base and passes a variable i to Base while setting its internal variable year to j.
What is happening? Rectangle rect; Triangle trgl; Polygon * ppoly1 = ▭ Polygon * ppoly2 = &trgl;
Two pointers to Polygon are declared. . These are assigned the addresses of rect and trgl, respectively, which are objects of type Rectangle and Triangle. This only works if Polygon is a base class. Dereferencing ppoly1 and ppoly2 (with *ppoly1 and *ppoly2) is valid and allows us to access the members of their pointed objects.
What happens if you don't add a virtual destructor on a base class where the derived classes are created using the new keyword? i.e. virtual ~Polygon() {};
When the derived classes are created using new and then they go out of scope the destructor on the base class will NOT be called, causing memory leaks. See: 12_polygon.cpp
Can suppressed functions that are made private in a derived class be accessed through pointers?
Yes, a pointer of the base class type will still have that functionality. See 15_supress.cpp
One of the key features of class inheritance is that a pointer to a derived class is type-compatible with a pointer to its _____________.
base class
What is the solution to the diamond problem?
create a virtual base class for the two parent classes to avoid two copies of the grandparent class class Student : virtual public Person { public: Student(int x):Person(x) { .... } };
When we use 'virtual' keyword, the __________________ of grandparent class is called by default even if the parent classes explicitly call a parameterized constructor.
default constructor
In C++, a ______________ object can be assigned to a base class object, but the other way is not possible.
derived class
______________________ doesn't occur when pointers or references to objects are passed as function arguments .
object slicing
A class that declares or inherits a virtual function is called a ____________________ class.
polymorphic
Virtual functions are binded at ________________.
runtime
Diamond problem
when two superclasses of a class have a common base class. The sub class then gets two copies of all attributes of superclass class, this causes ambiguities.