Top Banner
TCP1201 OOPDS 1 Inheritance
35
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Lecture03 inheritance

TCP1201 OOPDS1

Inheritance

Page 2: Lecture03 inheritance

TCP1201 OOPDS 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

Page 3: Lecture03 inheritance

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).

Page 4: Lecture03 inheritance

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.)

Page 5: Lecture03 inheritance

TCP1201 OOPDS 55

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.

Page 6: Lecture03 inheritance

TCP1201 OOPDS 66

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.

Page 7: Lecture03 inheritance

TCP1201 OOPDS 77

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.

Page 8: Lecture03 inheritance

TCP1201 OOPDS 88

Definition of Inheritance Inheritance is the mechanism which allows

a class B to inherit attributes and methods of a class A. We say "B inherits from A".

Objects of class B have direct access to non-private attributes and methods of class A.

If class B inherits from class A, then A is called the superclass/base class/parent class) of B. B is called the subclass/derived class/child class) of A.

Superclass is more general than subclass– Subclass is more specific than

superclass

Superclass/Base class/Parent class

Subclass/Derived class/

Child class

Is-a

Page 9: Lecture03 inheritance

TCP1201 OOPDS 99

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, room: string)

+ Student (name:string, CGPA:double)

Page 10: Lecture03 inheritance

TCP1201 OOPDS

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; }};

1010

Superclass: Human

Page 11: Lecture03 inheritance

TCP1201 OOPDS 1111

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.

Page 12: Lecture03 inheritance

TCP1201 OOPDS 1212

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);};

Page 13: Lecture03 inheritance

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.

Page 14: Lecture03 inheritance

TCP1201 OOPDS 1414

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; }or

Lecturer (string name, string room) : Human(name), room(room) { } // Correct.

Note that we are reusing existing code (Human constructor).

"calls" the Human constructor with the argument name.

Page 15: Lecture03 inheritance

TCP1201 OOPDS

Inheritance Exampleclass Human { string name; public: Human (string name) : name(name) {} void speak (string sentence) { cout << "My name is " << name << ". " << sentence << endl; }};class Lecturer : public Human { string room; public: Lecturer (string name, string room) : Human(name), room(room) {}};

Output:My name is Hugo. HaMy name is Lee. HiMy name is Sarah. Ho

class Student : public Human { double CGPA; public: Student (string name, double

CGPA) : Human(name), CGPA(CGPA) {}};

int main() { Human h("Hugo"); Lecturer l("Lee", "BR1111"); Student* s = new Student

("Sarah", 3.99); h.speak ("Ha"); l.speak ("Hi"); // Human::speak() s->speak ("Ho");// Human::speak() delete s;}

15

Page 16: Lecture03 inheritance

TCP1201 OOPDS

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) {} ...

1616

Simpler Code Maintenance

Page 17: Lecture03 inheritance

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, room: string)

+ Student (name: string, CGPA: double)

LocalStudent ForeignStudent

- icno: string - passportno: string

+ LocalStudent (name: string, CGPA: double, icno: string)

+ ForeignStudent (name: string, CGPA: double, passportno: string)

Page 18: Lecture03 inheritance

TCP1201 OOPDS 1818

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.

Page 19: Lecture03 inheritance

TCP1201 OOPDS 1919

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) {}};

Page 20: Lecture03 inheritance

TCP1201 OOPDS 2020

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};

Page 21: Lecture03 inheritance

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

C

Constructor for class A

Constructor for class B

Page 22: Lecture03 inheritance

TCP1201 OOPDS 2222

Diamond Inheritance Problem

A

C

B1 B2

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.

Page 23: Lecture03 inheritance

TCP1201 OOPDS 2323

Diamond Inheritance Problemclass A { ... };class B1: public A { ... };class B2: public A { ... };class C: public B1, public B2 { public: C(...) : B1(...), B2 (...) { }}; Solution: virtual inheritanceclass A {};class B1: virtual public A {};class B2: virtual public A {};class C: public B1, public B2 { public: C(...) : A(...), B1(...), B2 (...) {} // Must call super-superclass constructor.};

Virtual Inheritance

A

B1

C

B2

Page 24: Lecture03 inheritance

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.

Page 25: Lecture03 inheritance

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. ...};

Page 26: Lecture03 inheritance

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) { } ...};

Page 27: Lecture03 inheritance

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

Page 28: Lecture03 inheritance

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 z; public: void setZ (int z) { this->z = z; } int getZ() const { return z; }};class Sub: public Super { public: Sub(int z) { setZ (z); // superclaas' setZ }};

int main() { Sub s(3); cout << s.getZ() << endl; s.setZ (33); // Fine cout << s.getZ() << endl;}

Output:333

Page 29: Lecture03 inheritance

TCP1201 OOPDS

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 << "Eating\n"; } void speak() { cout << "I'm a human\n"; }};class Student : public Human { public: void speak() { // Override superclass' speak(). cout << "I'm a student\n"; }};

Page 30: Lecture03 inheritance

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.

Page 31: Lecture03 inheritance

TCP1201 OOPDS 31

Constructor vs. Destructor Call Orderclass Human { string name; public: Human(string name) : name(name) { cout << "Human " << name << " created.\n"; } ~Human() { cout << "Human " << name << " destroyed.\n"; }};

Output:Human Michael created.Student 111 created.Human Kelly created.Student 222 created.Student 222 destroyed.Human Kelly destroyed.Student 111 destroyed.Human Michael destroyed.

class Student : public Human { int id; public: Student (int id, string name) : Human(name), id(id) { cout << "Student " << id << " created.\n"; } ~Student() { cout << "Student " << id << " destroyed.\n"; }};

int main() { // create s1 Student s1 (111, "Michael"); Student *s2 = new Student (222, "Kelly"); // create s2 delete s2; // destroy s2} // destroy s1

Page 32: Lecture03 inheritance

TCP1201 OOPDS 32

Function Overridingclass Human { public: void eat() { cout << "Eating\n"; } void speak() { cout << "I'm a human\n"; }};class Student : public Human { public: void speak() { // Override superclass' speak(). cout << "I'm a student\n"; }};int main() { Human* h = new Human; Student* s = new Student; h->speak(); // call Human::speak() s->speak(); // call Student::speak() h->eat(); // call Human::eat() s->eat(); // call Human::eat() delete h; delete s;}

Output:

I'm a humanI'm a studentEatingEating

Page 33: Lecture03 inheritance

TCP1201 OOPDS

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.

Page 34: Lecture03 inheritance

TCP1201 OOPDS

Upcasting and Downcastingclass 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.}

Page 35: Lecture03 inheritance

TCP1201 OOPDS

Benefits of Upcasting

class Human { // Superclass public: void eat() { cout << "Eating\n"; }};class Lecturer : public Human { }; // Subclassclass Student : public Human { }; // Subclassvoid 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]; }}

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.