chapter 11: inheritance

26
1 Chapter 11: Inheritance Chapter 11: Inheritance Chapter Goals Chapter Goals To understand the concepts of To understand the concepts of inheritance and polymorphism inheritance and polymorphism To learn how inheritance is a tool To learn how inheritance is a tool for code reuse for code reuse To learn how to call base-class To learn how to call base-class constructors and member functions constructors and member functions To understand the difference To understand the difference between static and dynamic binding between static and dynamic binding To be able to implement dynamic To be able to implement dynamic binding with virtual functions binding with virtual functions

Upload: penha

Post on 04-Jan-2016

29 views

Category:

Documents


1 download

DESCRIPTION

Chapter 11: Inheritance. Chapter Goals To understand the concepts of inheritance and polymorphism To learn how inheritance is a tool for code reuse To learn how to call base-class constructors and member functions To understand the difference between static and dynamic binding - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Chapter 11: Inheritance

11

Chapter 11: Inheritance Chapter 11: Inheritance

Chapter GoalsChapter Goals• To understand the concepts of To understand the concepts of

inheritance and polymorphism inheritance and polymorphism • To learn how inheritance is a tool for To learn how inheritance is a tool for

code reuse code reuse • To learn how to call base-class To learn how to call base-class

constructors and member functions constructors and member functions • To understand the difference between To understand the difference between

static and dynamic binding static and dynamic binding • To be able to implement dynamic To be able to implement dynamic

binding with virtual functions binding with virtual functions

Page 2: Chapter 11: Inheritance

22

Derived ClassesDerived Classes Inheritance is a mechanism for enhancing existing working Inheritance is a mechanism for enhancing existing working

classes. classes. If a new class needs to be implemented and a class If a new class needs to be implemented and a class

representing a more general concept is already available, representing a more general concept is already available, then the new class can then the new class can inheritinherit from the existing class. from the existing class.

The existing, more general class is called the The existing, more general class is called the base classbase class. . The more specialized class that inherits from the base class The more specialized class that inherits from the base class

is called the is called the derived classderived class. . ExampleExample: :

class Manager : public Employee {class Manager : public Employee {public: public: … …new member functionsnew member functions private: private: … …new data membersnew data members };};

Class Class ManagerManager is derived, is derived, EmployeeEmployee is base class. is base class.

Page 3: Chapter 11: Inheritance

33

Derived ClassesDerived Classes Derived Class Definition: general syntaxDerived Class Definition: general syntax

class class Derived_class_name Derived_class_name : public : public Base_class_name Base_class_name {{     … new    … new features in derived classfeatures in derived class}; };

ExampleExample: : class Manager : public Employee { class Manager : public Employee {

public: public: Manager(string name, double salary, string dept); Manager(string name, double salary, string dept); string get_department() const; string get_department() const;

private: private: string department; string department;

};};

PurposePurpose: To define a class (the derived class) that : To define a class (the derived class) that inherits features from a base class. inherits features from a base class.

Page 4: Chapter 11: Inheritance

44

Derived ClassesDerived Classes All member functions and data members of the All member functions and data members of the

base class are automatically inherited by the base class are automatically inherited by the derived class. derived class.

ExampleExample: : Manager m; Manager m; m.set_salary(68000); m.set_salary(68000);

In the derived class definition you specify only In the derived class definition you specify only new member functions and data members. new member functions and data members.

ExampleExample: : class Manager : public Employee { class Manager : public Employee { public: public: Manager(string name, double salary, string dept); Manager(string name, double salary, string dept); string get_department() const; string get_department() const; private: private: string department; string department; }; };

Page 5: Chapter 11: Inheritance

55

Derived ClassesDerived Classes The diagram below shows the relationship The diagram below shows the relationship

between derived classes and corresponding between derived classes and corresponding base classes. The arrow with a hollow head base classes. The arrow with a hollow head indicates inheritance. indicates inheritance.

Page 6: Chapter 11: Inheritance

66

Example - Base Class : ClockExample - Base Class : Clock #ifndef __CLOCK_H_#ifndef __CLOCK_H_

#define __CLOCK_H_#define __CLOCK_H_   classclass Clock { Clock { publicpublic::    /**/**    Constructs a clock that can tell the local time.  Constructs a clock that can tell the local time.    @param use_military true if the clock uses military format  @param use_military true if the clock uses military format   */ */    ClockClock(bool use_military);(bool use_military);         

// returns the current location// returns the current location  string   string get_locationget_location() () constconst;;       // returns the hours in military format // returns the hours in military format  int   int get_hoursget_hours() () constconst;;

    // returns the minutes// returns the minutes

int int get_minutesget_minutes() () constconst;;        // returns true if military format// returns true if military format

    bool bool is_militaryis_military() () constconst;;  privateprivate::  bool military;  bool military; }; }; #endif  #endif 

Page 7: Chapter 11: Inheritance

77

Clock::Clock(bool use_military) {    military = use_military;} string Clock::get_location() const {    return "Local";} int Clock::get_hours() const {    Time now;    int hours = now.get_hours();    if (military) return hours;    if (hours == 0)        return 12;    else if (hours > 12)       return hours - 12;    else       return hours;}

Implementation of class Clock

int Clock::get_minutes() const {     Time now;  return now.get_minutes();  }    bool Clock::is_military() const {      return military;  } 

Page 8: Chapter 11: Inheritance

88

Example of Program Using Class Clock

#include <iostream> #include <iomanip> #include <string> using namespace std; #include "ccc_time.h" #include “Clock.h”

int main() {     Clock clock1(true);     Clock clock2(false);      bool more = true;    while (more)  {        cout << "Military time: "           << clock1.get_hours() << ":"           << setw(2) << setfill('0')           << clock1.get_minutes()           << setfill(' ') << "\n"; cout << "am/pm time: "       << clock2.get_hours() << ":"           << setw(2) << setfill('0')           << clock2.get_minutes()           << setfill(' ') << "\n";         cout << "Try again? (y/n) ";        string input;        getline(cin, input);        if (input != "y") more = false;    }    return 0; }

Page 9: Chapter 11: Inheritance

99

Derived ClassesDerived Classes The Clock class presented in clocks1.cpp provides a base The Clock class presented in clocks1.cpp provides a base

class that can tell the current local time. class that can tell the current local time.

You can set a clock to either "military" or "am/pm" format. You can set a clock to either "military" or "am/pm" format.

We will create a derived class, TravelClock that gains two We will create a derived class, TravelClock that gains two additional data fields: location and time_difference. additional data fields: location and time_difference.

Page 10: Chapter 11: Inheritance

1010

Derived Classes (cont.)Derived Classes (cont.)

The time for a The time for a TravelClockTravelClock is is computed by taking the local time computed by taking the local time and adding the time difference. and adding the time difference.

TravelClock clock("New York", 3); TravelClock clock("New York", 3);

cout << "The time in " cout << "The time in "

<< clock.get_location() << " is " << clock.get_location() << " is "

<< clock.get_hours() << ":" << clock.get_hours() << ":"

<< clock.get_minutes(); << clock.get_minutes();

Page 11: Chapter 11: Inheritance

1111

Derived Class (cont.)Derived Class (cont.) A A TravelClockTravelClock differs from a differs from a ClockClock in three ways: in three ways:

• Its objects store the location and time difference. Its objects store the location and time difference. • The The get_hoursget_hours function of the function of the TravelClockTravelClock adds the time adds the time

difference to the current time. difference to the current time. • The The get_locationget_location function returns the actual location, not the function returns the actual location, not the

string "Local".string "Local".

When the When the TravelClockTravelClock class inherits from the class inherits from the ClockClock class, it class, it needs only to spell out these three differences. needs only to spell out these three differences.

Specification of class Specification of class TravelClock TravelClock followsfollows. .

class TravelClock : public Clock {public:    TravelClock(bool mil, string loc, double off);    int get_hours() const;    string get_location() const;private:    string location;    int time_difference;};

Page 12: Chapter 11: Inheritance

1212

Calling the Base-Class ConstructorCalling the Base-Class Constructor

The constructor of a derived class has The constructor of a derived class has two tasks: two tasks: • Initialize the base object. Initialize the base object. • Initialize all data members. Initialize all data members.

Frequently, a derived-class constructor Frequently, a derived-class constructor must invoke the base-class constructor must invoke the base-class constructor before initializing the derived-class before initializing the derived-class data. data.

Page 13: Chapter 11: Inheritance

1313

Calling the Base-Class Constructor (cont.)Calling the Base-Class Constructor (cont.)

Here, we call the Here, we call the ClockClock constructor with the parameter constructor with the parameter mil mil

before executing the code inside the before executing the code inside the {}.{}.

TravelClock::TravelClock(bool mil, string loc, int diff) : Clock(mil) { location = loc; time_difference = diff; while (time_difference < 0) time_difference = time_difference + 24; }

• If you omit the base-class constructor, then the base object is constructed with the default constructor of the base class.

• If the base class has no default constructor, then you have to explicitly call the base-class constructor in the derived-class constructor.

Page 14: Chapter 11: Inheritance

1414

Calling the Base-Class Constructor Calling the Base-Class Constructor (Syntax Constructor with Base-Class Initializer) (Syntax Constructor with Base-Class Initializer)

Constructor with Base-Class Initializer Constructor with Base-Class Initializer

Derived_class_name::DerivedDerived_class_name::Derived__class_name(class_name(parameter listparameter list)) :: Base_class_name(Base_class_name(expressionsexpressions))

{{ … … statementsstatements inside the constructor inside the constructor … …

}}

ExampleExample::

Manager::Manager(string name, double salary,Manager::Manager(string name, double salary, string dept) string dept) : Employee(name, salary) : Employee(name, salary)

{ { department = dept; department = dept;

} }

PurposePurpose: Supply the implementation of a constructor, initializing : Supply the implementation of a constructor, initializing the base class before the body of the derived-class constructor.the base class before the body of the derived-class constructor.

Page 15: Chapter 11: Inheritance

1515

Calling Base-Class Member FunctionsCalling Base-Class Member Functions

Suppose Suppose B::f B::f is a function in the base class. The is a function in the base class. The the derived class the derived class DD can take three kinds of actions. can take three kinds of actions.

• The derived class can The derived class can extendextend B::fB::f by supplying a new by supplying a new implementation that refers to the base-class implementation that refers to the base-class implementation. implementation.

For example, the For example, the TravelClock::get_hoursTravelClock::get_hours function is an function is an extension of extension of Clock::get_hours.Clock::get_hours.

• The derived class can The derived class can replacereplace B::f B::f by supplying a new by supplying a new implementation that is unrelated to the base-class implementation that is unrelated to the base-class implementation. implementation.

For example, For example, TravelClock::get_locationTravelClock::get_location is a replacement is a replacement for for Clock::get_location. Clock::get_location.

• The derived class can The derived class can inheritinherit B::fB::f by not supplying an by not supplying an implementation for implementation for ff. .

For example, For example, TravelClockTravelClock inherits inherits Clock::get_minutes Clock::get_minutes and and Clock::is_militaryClock::is_military. .

Page 16: Chapter 11: Inheritance

1616

Calling Base-Class Member FunctionsCalling Base-Class Member Functions A member function called without a parameter is called A member function called without a parameter is called

through the implicit parameter object of the derived class.through the implicit parameter object of the derived class.

if (is_military()) //it uses military time if (is_military()) //it uses military time return (h + time_difference) % 24; return (h + time_difference) % 24;

When the base class and the derived class have a member When the base class and the derived class have a member function with the same name, you must be more specific function with the same name, you must be more specific which function you want to call. which function you want to call.

int TravelClock::get_hours() const { int TravelClock::get_hours() const { int h = Clock::get_hours(); int h = Clock::get_hours(); . . . . . . } }

The following call would die in an infinite recursion. The following call would die in an infinite recursion.

int TravelClock::get_hours() const { int TravelClock::get_hours() const { int h = get_hours(); int h = get_hours();

. . . . . . } }

calls

base-cl

ass

calls

base-cl

ass

function

function

calls itself!!calls itself!!Not correct in Not correct in this case!!!this case!!!

Page 17: Chapter 11: Inheritance

1717

class TravelClock : public Clock { public: /**       Constructs a travel clock that can tell the time       at a specified location        @param mil true if the clock uses military format        @param loc the location        @param diff the time difference from the local time     */     TravelClock(bool mil, string loc, int diff);     string get_location() const;     int get_hours() const;

  private:     string location;     int time_difference;  };   

Example: Specification and Implementation of class TravelClock

Page 18: Chapter 11: Inheritance

1818

TravelClock::TravelClock(bool mil, string loc, int diff)     : Clock(mil) {     location = loc;     time_difference = diff;     while (time_difference < 0)         time_difference = time_difference + 24;  }    string TravelClock::get_location() const {     return location;  }    int TravelClock::get_hours() const {     int h = Clock::get_hours();     if (is_military())        return (h + time_difference) % 24;     else {        h = (h + time_difference) % 12;        if (h == 0) return 12;        else return h;     }  }

Implementation of class TravelClock

Page 19: Chapter 11: Inheritance

1919

… main function of program Clocks2.cpp

int main() {     Clock clock1(true);     TravelClock clock2(true, "Rome", 9);     TravelClock clock3(false, "Tokyo", -7);       cout << clock1.get_location() << " time: "         << clock1.get_hours() << ":"        << setw(2) << setfill('0')         << clock1.get_minutes()         << setfill(' ') << "\n";     cout << clock2.get_location() << " time: "         << clock2.get_hours() << ":"        << setw(2) << setfill('0')         << clock2.get_minutes()         << setfill(' ') << "\n";     cout << clock3.get_location() << " time: "         << clock3.get_hours() << ":"        << setw(2) << setfill('0')         << clock3.get_minutes()         << setfill(' ') << "\n";     return 0;  }

Example of program using the TravelClock class

Page 20: Chapter 11: Inheritance

2020

PolymorphismPolymorphism You will find that there is quite a bit of repetitive code in You will find that there is quite a bit of repetitive code in

clocks2.cpp. clocks2.cpp.

It would be nicer if all three clocks were collected in a vector, It would be nicer if all three clocks were collected in a vector, as attempted next: as attempted next:

vector<Clock> clocks(3);vector<Clock> clocks(3); clocks[0] = Clock(true); clocks[0] = Clock(true); clocks[1] = TravelClock(true, "Rome", 9); clocks[1] = TravelClock(true, "Rome", 9); clocks[2] = TravelClock(false, "Tokyo", -7); clocks[2] = TravelClock(false, "Tokyo", -7);  

for (int i = 0; i < clocks.size(); i++) {for (int i = 0; i < clocks.size(); i++) {   cout << clocks[i].get_location() << " time: "   cout << clocks[i].get_location() << " time: "     << clocks[i].get_hours() << ":"     << clocks[i].get_hours() << ":"     << setw(2) << setfill('0'     << setw(2) << setfill('0'     << clocks[i].get_minutes()     << clocks[i].get_minutes()     << setfill(' ') << "\n";     << setfill(' ') << "\n"; }  }

Unfortunately, this does not work as expected. The output of Unfortunately, this does not work as expected. The output of this program is: this program is:

Local time is 21:15Local time is 21:15   Local time is 21:15Local time is 21:15   Local time is 21:15 Local time is 21:15

This is validsince everyobject of typeTravelClockis also of typeClock

Page 21: Chapter 11: Inheritance

2121

PolymorphismPolymorphism The compiler realizes that a The compiler realizes that a TravelClockTravelClock is a special case of a is a special case of a ClockClock, and , and

permits the assignment permits the assignment

clocks[1] = TravelClock(true, "Rome", 9); clocks[1] = TravelClock(true, "Rome", 9);

However, there is no room to store the derived-class data. However, there is no room to store the derived-class data.

That data simply gets sliced away when a derived-class object is assigned to a That data simply gets sliced away when a derived-class object is assigned to a base-class variable. base-class variable.

The following figure illustrates the area that is copied with the previous The following figure illustrates the area that is copied with the previous statement.statement.

This portion of aTravelClock is copiedto the Clock object inthe previous assignment statement.

Page 22: Chapter 11: Inheritance

2222

Polymorphism (cont.)Polymorphism (cont.) A base-class pointer can point to a derived class object. A base-class pointer can point to a derived class object.

(The reverse is an error). (The reverse is an error).

By creating a vector of pointers to the base-class type, we By creating a vector of pointers to the base-class type, we can hold a collection of both base-class and derived-class can hold a collection of both base-class and derived-class objects. objects.

vector<Clock*> clocks(3); vector<Clock*> clocks(3); // populate clocks // populate clocks clocks[0] = new Clock(true); clocks[0] = new Clock(true); clocks[1] = new TravelClock(true, "Rome", 9); clocks[1] = new TravelClock(true, "Rome", 9);

clocks[2] = new TravelClock(false, "Tokyo", -7); clocks[2] = new TravelClock(false, "Tokyo", -7);

Pointers to the various clock objects all have the same size Pointers to the various clock objects all have the same size - the size of a memory address - even though the objects - the size of a memory address - even though the objects themselves may have different sizes. themselves may have different sizes.

Since every Since every TravelClockTravelClock is a special case of a is a special case of a ClockClock, the , the starting address of a TravelClock object is the starting starting address of a TravelClock object is the starting address of a Clock object. address of a Clock object.

Page 23: Chapter 11: Inheritance

2323

Polimorphisms (cont.)

A pointer to Clockis also a validpointer to objectsof type TravelClock.

This figure illustratesthe memory organization after thethree assignmentstatements in the code.

Page 24: Chapter 11: Inheritance

2424

PolymorphismPolymorphism Unfortunately, the following code does not work either! Unfortunately, the following code does not work either!

cout << clocks[i]->get_location() cout << clocks[i]->get_location() << " time: " << " time: " << clocks[i]->get_hours() << clocks[i]->get_hours() << ":" << setw(2) << setfill('0') << ":" << setw(2) << setfill('0') << clocks[i]->get_minutes() << clocks[i]->get_minutes() << setfill(' ') << "\n"; << setfill(' ') << "\n";

The output is still:The output is still:

Local time is 21:15 Local time is 21:15 Local time is 21:15 Local time is 21:15 Local time is 9:15 Local time is 9:15

The reason is that both, The reason is that both, ClockClock and and TravelClock,TravelClock, have a have a get_locationget_location and a and a get_hoursget_hours member function. member function.

The compiler calls the The compiler calls the ClockClock member function because the member function because the pointer is of type pointer is of type ClockClock*. *.

But the correct result should be: Local time: 11:53 Rome time: 20:53 Tokyo time: 4:53

Page 25: Chapter 11: Inheritance

2525

Polymorphism (cont.)Polymorphism (cont.) You must alert the compiler that the function call needs to You must alert the compiler that the function call needs to

be preceded by the appropriate function selection, which be preceded by the appropriate function selection, which can be a different one for every iteration in the loop. can be a different one for every iteration in the loop.

Such a selection/call combination is called Such a selection/call combination is called dynamic bindingdynamic binding. . The traditional call, which always invokes the same The traditional call, which always invokes the same

function, is called function, is called static bindingstatic binding. . To tell the C++ compiler that a particular function needs to To tell the C++ compiler that a particular function needs to

be bound dynamically, the function must be tagged as be bound dynamically, the function must be tagged as virtualvirtual. .

class Clock { public:    Clock(bool use_military);    virtual string get_location() const;    virtual int get_hours() const;    int get_minutes() const;    bool is_military() const; private:    . . . };

With this,the previouscode worksas expected.

Page 26: Chapter 11: Inheritance

2626

Polymorphism - Virtual Function DefinitionPolymorphism - Virtual Function Definition• Syntax of Virtual Function Definition

class Class_name { virtual return_type function_name(parameter list); . . . };

• Example:

class Employee { public: virtual double get_salary();

. . . };

• Purpose: Define a dynamically bound function that can be redefined in derived classes. When the function is called, the actual type of the implicit parameter determines which version of the function to execute.