The document discusses inheritance in object-oriented programming. It defines inheritance as a mechanism where a subclass inherits attributes and behaviors from its superclass. This allows code reuse and simplifies maintenance. The key points covered include inheritance terminology like "is-a" relationship; defining subclasses using colon syntax; initializing superclass constructors from subclasses; multiple levels and types of inheritance like multiple and diamond inheritance; protected access privilege; function overriding; and the call order of constructors and destructors between superclasses and subclasses.
2. Learninig Objectives
To understand inheritance terminology
To understand Object Relationship Diagrams (ORD)
To understand how to define subclasses
To understand multiple inheritance
To understand diamond inheritance and virtual
inheritance
To understand the call order of constructor and
destructor in inheritance
To understand function overriding
To understand protected access privilege
To understand upcasting & downcasting
TCP1201 OOPDS
3. Inheritance
By nature we commonly group objects that have a
common attributes and behaviors into classes
(categories)., e.g. animals, vehicles, and human.
Under each of these classes there can be 0, 1, or more
subclasses (subcategories).
TCP1201 OOPDS
4. Example 1/2
Under the animal class, we can create three subclasses:
bird, mammal and fish.
Animal, bird, mammal and fish are classes.
Bird, mammal and fish are subclasses of animal.
Eagle, parrot, whale, monkey, goldfish and shark are
instances/objects. (They can actually be sub-subclasses.)
TCP1201 OOPDS
5. The "is-a" Relationship
Note the following statements:
– Eagle is a bird. Parrot is a bird. Both are also animals.
– Cat is a mammal. Monkey is a mammal. Both are also animals.
– Goldfish is a fish. Shark is a fish. Both are also animals.
A bird is different from a mammal, a mammal is different from a
fish, and a fish is different from a bird.
Even though they are all different among one another, they are the
same in regard that they are all animals.
TCP1201 OOPDS
6. Example 2/2
Under the Human class, we can create 2 subclasses:
Lecturer and Student.
Sharaf and Manoj are instances of Lecturer. Tom and John
are instances of Student.
Sharaf, Manoj, Tom and John are also Humans.
TCP1201 OOPDS
7. Inheritance Terminology
The "is-a" relationship between a superclass and its
subclasses is commonly referred to as inheritance.
We say that a subclass "inherits from"/"derives from" a
superclass. Example: Bird inherits from Animal.
Subclass inherits all the characteristics (attributes and
methods) from its superclass.
– All objects of Bird have a common set of attributes
and methods of Bird, and also inherit a common set of
attributes and behaviors from Animal.
– Example: If animals have skin, then birds also have
skin.
Inheritance promotes code reuse and simplifies code
maintenance in the long run.
TCP1201 OOPDS
8. Definition of Inheritance
Inheritance is the mechanism which allows
a class B to inherit attributes and methods
Superclass/
of a class A. We say "B inherits from A".
Base class/
Objects of class B have direct access to Parent class
non-private attributes and methods of
class A.
Is-a
If class B inherits from class A, then A is
called the superclass/base class/parent Subclass/
class) of B. B is called the Derived class/
Child class
subclass/derived class/child class) of A.
Superclass is more general than subclass
– Subclass is more specific than
superclass
TCP1201 OOPDS
9. Inheritance in UML Class Diagram
From the following UML Class Diagram
– We know that Human is the superclass.
– Lecturer and Student are subclasses of Human class.
Human
- name: string
+ Human (name: string)
+ speak (sentence: string): void
Lecturer Student
- room: string - CGPA: double
+ Lecturer (name: string, + Student (name:string,
room: string) CGPA:double)
TCP1201 OOPDS
10. Superclass: Human
The C++ Definition for the superclass Human:
class Human {
string name;
public:
Human(string name) : name(name) {}
void speak(string sentence) {
cout << "My name is "
<< name << ". "
<< sentence << endl; }
};
TCP1201 OOPDS
11. Defining Subclasses
To indicate that a subclass inherits from superclass, we
use a single colon ":", followed by an access privilege
keyword (usually public) and the name of the superclass
in the declaration.
class subclass : public superclass
: <constructor initialization list>
{
...
};
In most cases, subclass' constructor should initialize
superclass' attributes.
TCP1201 OOPDS
12. Subclass Lecturer
Hence, the declaration for Lecturer is as follows:
class Lecturer : public Human {
string room;
public:
Lecturer (string name, // 'name' is for initializing
// superclass' attribute.
string room);
};
TCP1201 OOPDS
13. Initializing Superclass from Subclass
Wrong way of initializing superclass from subclass:
Lecturer (string name, string room) {
this->name = name; // Compile-error.
this->room = room;
}
or
Lecturer (string name, string room)
: name(name), room(room) {} // Compile-error.
The reason is name is a private attribute of superclass
hence cannot be directly accessed by subclass.
TCP1201 OOPDS 13
14. Calling Superclass Constructor
The correct way of initializing superclass is to invoke
superclass constructor at subclass' constructor initializer
list.
Lecturer (string name, string room)
: Human(name) { // Correct.
this->room = room; "calls" the Human constructor with
} the argument name.
or
Lecturer (string name, string room)
: Human(name), room(room) { } // Correct.
Note that we are reusing existing code (Human
constructor).
TCP1201 OOPDS
15. Inheritance Example
class Human { class Student : public Human {
string name; double CGPA;
public: public:
Human (string name)
: name(name) {} Student (string name, double
void speak (string sentence) { CGPA)
cout << "My name is " : Human(name), CGPA(CGPA) {}
<< name << ". " };
<< sentence << endl;
} int main() {
};
class Lecturer : public Human { Human h("Hugo");
string room; Lecturer l("Lee", "BR1111");
public: Student* s = new Student
Lecturer (string name, ("Sarah", 3.99);
string room) h.speak ("Ha");
: Human(name), room(room) {} l.speak ("Hi"); // Human::speak()
};
s->speak ("Ho");// Human::speak()
Output: delete s;
My name is Hugo. Ha }
My name is Lee. Hi
My name is Sarah. Ho
TCP1201 OOPDS
16. Simpler Code Maintenance
Now assume that both Lecturer and Student need a
new attribute called address. Instead of adding the
address at subclasses Lecturer and Student
directly, we should add the address at superclass Human
because the attribute will be inherited by both Lecturer
and Student.
The C++ Definition for the superclass Human:
class Human {
string name;
string address;
public:
Human(string name, string address = "")
: name(name), address(address) {}
...
TCP1201 OOPDS
17. Multiple Levels of Inheritance
We can have more than one level of inheritance.
For example, the Student class can be the superclass of
LocalStudent and ForeignStudent. (Ignore the attribute
address we discuss in previous slide.)
Human
- name: string
+ Human (name: string)
+ speak (sentence: string): void
Lecturer Student
- room: string - CGPA: double
+ Lecturer (name: string, + Student (name: string,
room: string) CGPA: double)
LocalStudent ForeignStudent
- icno: string - passportno: string
+ LocalStudent (name: string, + ForeignStudent (name: string,
CGPA: double, icno: string) CGPA: double, passportno: string)
TCP1201 OOPDS
18. Multiple Levels of Inheritance
A subclass inherits the attributes and methods of all of its
superclasses:
– A ForeignStudent object will, therefore, inherit:
• all of the attributes and methods of Human class,
• plus the attributes and methods of Student class,
• plus the attributes and methods of ForeignStudent
class.
TCP1201 OOPDS
19. Multiple Levels of Inheritance
A subclass constructor can invoke only the immediate
superclass constructor, not the super-superclass
constructor, unless virtual inheritance is used.
class LocalStudent : public Student {
string icno;
public:
LocalStudent (string name, double CGPA, string icno)
: Human(name), // Compile error, attempt to call
// super-superclass constructor.
Student(name, CGPA),
icno(icno) {}
};
TCP1201 OOPDS
20. Multiple Levels of Inheritance
Sample constructor for LocalStudent and
ForeignStudent.
class LocalStudent : public Student {
string icno;
public:
LocalStudent (string name, double CGPA, string icno)
: Student(name, CGPA), // Call immediate superclass constructor, okay
icno(icno) {}
};
class ForeignStudent : public Student {
string passportno;
public:
ForeignStudent (string name, double CGPA, string passportno)
: Student(name, CGPA), passportno(passportno) {} // okay
};
TCP1201 OOPDS
21. Multiple Inheritance
Multiple inheritance is NOT the same as "multiple levels of
Inheritance".
Multiple inheritance occurs when a class has 2 or more
direct/immediate superclasses.
Use comma "," to separate surperclasses.
class C : public A, public B {
public:
C(…) : A(…), B(…) // Constructor initialization list.
{}
}; A B
Constructor Constructor
for class A for class B
C
TCP1201 OOPDS
22. Diamond Inheritance Problem
Multiple inheritance may introduce diamond inheritance
problem, which arises when 2 classes B1 and B2 inherit
from A, and class C inherits from both B1 and B2.
The pronlem is C would have duplicate sets (2 sets) of
the members inherited from A, which might not be
desirable.
If one set of members of A is preferred at C, we can use
virtual inheritance to avoid duplicate sets.
A
B1 B2
C
TCP1201 OOPDS
23. Virtual Inheritance
Diamond Inheritance Problem
class A { ... };
class B1: public A { ... };
class B2: public A { ... }; A
class C: public B1, public B2 {
public:
C(...) : B1(...), B2 (...) { }
}; B1 B2
Solution: virtual inheritance
class A {};
class B1: virtual public A {};
class B2: virtual public A {};
C
class C: public B1, public B2 {
public:
C(...) : A(...), B1(...), B2 (...) {}
// Must call super-superclass constructor.
};
TCP1201 OOPDS
24. protected Access Privilege
Recall from the previous lecture the following classes:
class Human {
string name; // private
...
};
class Lecturer : public Human {
string room;
public:
Lecturer (string name, string room)
: Human(name), room(room) {} // 'name' is private in Human
...
};
The reason we have to initialize the attribute name via
constructor initialization list is subclass cannot access
superclass' private members.
TCP1201 OOPDS
25. protected Access Privilege
If a class member is declared as protected, then it is
accessible to the class itself and its subclasses.
class Human {
protected:
string name;
...
};
class Lecturer : public Human {
string room;
public:
Lecturer (string name, string room) {
this->name = name; // Fine since 'name' is protected.
...
};
TCP1201 OOPDS
26. protected Access Privilege
However, same as private member, a protected member of
a superclass is not accessible at subclass' constructor
initilizer list.
class Human {
protected:
string name;
...
};
class Lecturer : public Human {
string room;
public:
Lecturer (string name, string room) {
: name(name), // Error, 'name' is not accessible here.
room(room) { }
...
};
TCP1201 OOPDS
27. protected Access Privilege
We use hash symbol "#" to denote protected access
privilege in UML Class Diagram.
Human
# name: string
+ Human (name: string)
+ speak (sentence: string): void
TCP1201 OOPDS
28. Accessing Superclass' Private Attribute
Subclass can access/modify superclass' private
attributes indirectly via the public/protected get/set
methods provided by superclass.
class Super { int main() {
int z; Sub s(3);
public: cout << s.getZ()
void setZ (int z) { << endl;
this->z = z; s.setZ (33); // Fine
} cout << s.getZ()
int getZ() const { return z; } << endl;
}; }
class Sub: public Super {
public:
Sub(int z) { Output:
setZ (z); // superclaas' setZ 3
} 33
};
TCP1201 OOPDS
29. Function Overriding
A subclass can override a superclass method by supplying
a new version of that method with the same signature.
When the method is invoked in the subclass, the subclass
version is automatically selected.
class Human {
public:
void eat() { cout << "Eatingn"; }
void speak() { cout << "I'm a humann"; }
};
class Student : public Human {
public:
void speak() { // Override superclass' speak().
cout << "I'm a studentn";
}
};
TCP1201 OOPDS
30. Constructor vs. Destructor Call
Order in Inheritance
When creating instances of a subclass (or derived
class), the constructors finish its execution from the
superclass(es) and moving downwards towards the
subclass itself.
When destroying instances of a subclass, the
destructors finish its execution from the subclass itself
and moving upwards towards the superclass(es).
The call order of destructors is the reverse of the call
order of constructors.
TCP1201 OOPDS
31. 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. } // destroy s1
Human Michael destroyed.
TCP1201 OOPDS
32. Function Overriding
class Human {
public:
void eat() { cout << "Eatingn"; }
void speak() { cout << "I'm a humann"; }
};
class Student : public Human {
public:
void speak() { // Override superclass' speak().
cout << "I'm a studentn";
}
};
int main() {
Human* h = new Human;
Student* s = new Student; 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
delete h; Eating
delete s;
}
TCP1201 OOPDS
33. Upcasting and Downcasting
An object of subclass can be treated as an
object/pointer/reference of its superclass, and vice
versa.
Upcasting: casting a subclass object as superclass.
– Can be implicit.
– Widely used in polymorphism (Lecture 4).
Downcasting: casting a superclass object as
subclass.
– Must be explicit.
– Rarely used, and is error-proned.
TCP1201 OOPDS
34. Upcasting and Downcasting
class Super { };
class Sub : public Super { };
int main() {
Super a; // a Super object.
Sub b; // a Sub object.
Sub* pb = &b; // Sub pointer points to Sub object.
Super* pa = pb;// Super pointer points to Sub object,
// ok, implicit upcasting.
pa = &b; // Ok, implicit upcasting.
Super& ra = b; // Super reference references a Sub object,
// ok, implicit upcasting.
pa = &a; // Super pointer points to Super object.
pb = pa; // Sub pointer points to Super object,
// compile-error, implicit downcasting.
pb = (Sub*) pa; // Ok, explicit downcasting.
Sub& rb1 = a; // Compile-error, implicit downcasting.
Sub& rb2 = (Sub&) a; // Ok, explicit downcasting.
pa = dynamic_cast<Super*>(&b); // Ok, explicit upcasting.
pa = static_cast<Super*>(&b); // Ok, explicit upcasting.
}
TCP1201 OOPDS
35. Benefits of Upcasting
Upcasting allows us to use an array of superclass
pointers to point to objects from subclasses.
Another benefit is we can pass subclass object to a
function parameter of type superclass pointer/reference.
class Human { // Superclass
public:
void eat() { cout << "Eatingn"; }
};
class Lecturer : public Human { }; // Subclass
class Student : public Human { }; // Subclass
void callEat (Human & h) { // Superclass reference.
h.eat();
}
int main() {
Human* h[3] = { new Human, new Lecturer, new Student};
for (int i = 0; i < 3; i++) {
h[i]->eat();
callEat (*h[i]);
delete h[i];
}
}
TCP1201 OOPDS