LECTURE 10
Inheritance (Part 2)
Computer Programming II
Constructor vs. Destructor Call
Order in Inheritance
• When creating instances of a subclass (or derived class), the constructors are
called starting at the highest point in the inheritance hierarchy (the most
general superclass/base class) and moving downwards towards the subclass.
• When destroying instances of a subclass, the destructors are called starting
at the subclass itself and moving upwards through the superclass(es).
• The call order of destructors is the reverse of the call order of constructors.
Computer Programming II
Constructor vs. Destructor Call Order
class Human { class Student : public Human {
string name; int id;
public: public:
Human(string name) : name(name) { Student (int id, string name)
cout << "Human " << name : Human(name), id(id) {
<< " created.\n"; } cout << "Student " << id
~Human() { << " created.\n"; }
cout << "Human " << name ~Student() {
<< " destroyed.\n"; } cout << "Student " << id
}; << " destroyed.\n"; }
};
Output:
Human Michael created. int main() {
Student 111 created. // create s1
Human Kelly created. Student s1 (111, "Michael");
Student 222 created. Student *s2 = new Student
Student 222 destroyed. (222, "Kelly"); // create s2
Human Kelly destroyed. delete s2; // destroy s2
Student 111 destroyed. return 0;
Human Michael destroyed. } // destroy s1
Computer Programming II 3
Function Overriding
• A subclass can override a superclass method (member function) by
supplying a new version of that method with the same signature.
• When the method is mentioned by name in the subclass, the subclass
version is automatically selected.
Computer Programming II
Function Overriding
class Human {
public:
void eat() { cout << "Eating\n"; }
void speak() { cout << "I'm a human\n"; }
};
class Student : public Human {
public:
void speak() { // override superclass
cout << "I'm a student\n";
}
};
int main() {
Human h;
Student s; Output:
h.speak(); // call Human::speak()
s.speak(); // call Student::speak() I'm a human
h.eat(); // call Human::eat() I'm a student
s.eat(); // call Human::eat() Eating
return 0; Eating
}
Computer Programming II
protected Access Privilege
• Recall from the previous lecture the following classes:
class Lecturer : public Human
public:
Lecturer (string name, string room)
: Human (name) { // name is private in Human
...
};
• One reason we have to initialize the attribute name via
constructor initialization list is subclass cannot access
superclass' private members
• If you insist to make superclass' members accessible to the
subclasses, use protected access privilege
Computer Programming II
protected Access Privilege
• If a class’ members are declared as protected, then they are
accessible to the class itself and its subclasses.
• Recall from the previous lecture the following classes:
class Human {
protected:
string name;
...
};
class Lecturer : public Human
public:
Lecturer (string name, string room) {
this->name = name; // Fine since name is protected
...
};
Computer Programming II
protected Access Privilege
• We use hash symbol "#" to denote protected access privilege in
UML Class Diagram and ORD
Human
# name: string
+ Human (name: string)
+ speak (sentence: string): void
• Granting superclass' attributes protected access privilege seems
making coding simpler, but it actually degrades encapsulation
and code reusability
Computer Programming II
P Private and Protected
Inheritance
• Recall that in declaring our subclasses, we used the keyword
public:
class Lecturer : public Human {
...
};
• When deriving a class from a superclass, the superclass may be
inherited as public, protected or private.
Computer Programming II
Public, Private and Protected Inheritance
• Superclass' private member is always not accessible in
subclass regardless public, private or protected
Inheritance.
• In public inheritance, all superclass' public and protected
members will retain their access privilege in the subclass.
• In protected inheritance, all superclass' public and
protected will be protected in subclass.
• In private inheritance, all superclass' public and protected
members will be private in subclass.
Computer Programming II
public Inheritance
class Super {
public: int x; x is public in class Sub
protected: int y; y is protected in class Sub
private: int z; z is not accessible in class Sub
};
class Sub: public Super {
public:
Sub() {
x = 1; // Fine x is public in main
y = 2; // Fine y is not accessible in main
z = 3; // Error z is not accessible in main
}
};
int main() { All superclass' public and
Sub s; protected members will retain
s.x = 11; // Fine their access privilege in the
s.y = 22; // Error subclass.
s.z = 33; // Error
return 0;
Computer Programming II
protected Inheritance
class Super {
public: int x; x is protected in class Sub
protected: int y; y is protected in class Sub
private: int z; z is not accessible in class Sub
};
class Sub: protected Super {
public:
Sub() {
x = 1; // Fine x is not accessible in main
y = 2; // Fine y is not accessible in main
z = 3; // Error z is not accessible in main
}
};
int main() { All superclass' public and
Sub s; protected members will be
s.x = 11; // Error protected in the subclass.
s.y = 22; // Error
s.z = 33; // Error
return 0;
Computer Programming II
private Inheritance
class Super {
public: int x; x is private in class Sub
protected: int y; y is private in class Sub
private: int z; z is not accessible in class Sub
};
class Sub: private Super {
public:
Sub() {
x = 1; // Fine x is not accessible in main
y = 2; // Fine y is not accessible in main
z = 3; // Error z is not accessible in main
}
};
int main() { All superclass' public and
Sub s; protected members will be
s.x = 11; // Error private in the subclass.
s.y = 22; // Error
s.z = 33; // Error
return 0;
Computer Programming II
Public, Private and Protected Inheritance
• To allow subclass to access/change superclass' private attributes,
provide public/protected get/set methods at superclass.
class Super { int main() {
int z; Sub s;
public: cout << s.getZ()
void setZ (int zz) { z = zz; } << endl;
int getZ() const { return z; } s.setZ (33); // Fine
}; cout << s.getZ()
class Sub: public Super { << endl;
public: return 0;
Sub() { }
setZ (3); // superclaas' setZ
}
}; Output:
3
33
Computer Programming II
Upcasting and Downcasting
• An object/pointer of subclass can be treated as an object/pointer
of its superclass.
• Subclass object/pointer can be implicitly converted to superclass
object/pointer, but not vice-versa.
• Superclass object/pointer must be explicitly converted to
subclass object/pointer.
• Upcasting: casting a subclass to superclass.
• Can be implicit
• Downcasting: casting a superclass to subclass.
• Must be explicit
• Upcasting is widely used in polymorphism (Lectures 10-11)
• Downcasting is rarely used, and error-prone
Computer Programming II
Upcasting and Downcasting
class Super { };
class Sub : public Super { };
int main () {
Super a; // a Super object
Super * pa; // a Super pointer
Sub b; // a Sub object
Sub * pb; // a Sub pointer
pb = &b;
pa = pb; // implicit upcasting
pa = &b; // implicit upcasting
pb = pa; // invalid downcasting
pb = (Sub*) pa; // explicit downcasting
pa = dynamic_cast<Super*>(&b); // ok, explicit upcasting
pa = static_cast<Super*>(&b); // ok, explicit upcasting
Computer Programming II