1 / 26

Chapter 11: Inheritance

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

penha
Télécharger la présentation

Chapter 11: Inheritance

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 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 • To be able to implement dynamic binding with virtual functions

  2. Derived Classes • Inheritance is a mechanism for enhancing existing working classes. • If a new class needs to be implemented and a class representing a more general concept is already available, then the new class can inherit from the existing class. • The existing, more general class is called the base class. • The more specialized class that inherits from the base class is called the derived class. Example: class Manager : public Employee { public: …new member functions private: …new data members }; Class Manager is derived, Employee is base class.

  3. Derived Classes • Derived Class Definition: general syntax class Derived_class_name : public Base_class_name {   … new features in derived class}; Example: class Manager : public Employee { public: Manager(string name, double salary, string dept); string get_department() const; private: string department; }; • Purpose: To define a class (the derived class) that inherits features from a base class.

  4. Derived Classes • All member functions and data members of the base class are automatically inherited by the derived class. Example: Manager m; m.set_salary(68000); • In the derived class definition you specify only new member functions and data members. Example: class Manager : public Employee { public: Manager(string name, double salary, string dept); string get_department() const; private: string department; };

  5. Derived Classes • The diagram below shows the relationship between derived classes and corresponding base classes. The arrow with a hollow head indicates inheritance.

  6. Example - Base Class : Clock #ifndef __CLOCK_H_ #define __CLOCK_H_ class Clock {public:/**  Constructs a clock that can tell the local time.  @param use_military true if the clock uses military format */Clock(bool use_military); // returns the current location  string get_location() const; // returns the hours in military format  int get_hours() const; // returns the minutes int get_minutes() const;// returns true if military format   bool is_military() const;private:  bool military; }; #endif 

  7. Implementation of class Clock 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;elseif (hours > 12)return hours - 12;elsereturn hours;} int Clock::get_minutes() const {     Time now;return now.get_minutes();  }  bool Clock::is_military() const {return military;  }

  8. Example of Program Using Class Clock 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; } #include <iostream>#include <iomanip>#include <string>usingnamespace std;#include "ccc_time.h"#include “Clock.h”

  9. Derived Classes • The Clock class presented in clocks1.cpp provides a base class that can tell the current local time. • You can set a clock to either "military" or "am/pm" format. • We will create a derived class, TravelClock that gains two additional data fields: location and time_difference.

  10. Derived Classes (cont.) • The time for a TravelClock is computed by taking the local time and adding the time difference. TravelClock clock("New York", 3); cout << "The time in " << clock.get_location() << " is " << clock.get_hours() << ":" << clock.get_minutes();

  11. Derived Class (cont.) • A TravelClock differs from a Clock in three ways: • Its objects store the location and time difference. • The get_hours function of the TravelClock adds the time difference to the current time. • The get_location function returns the actual location, not the string "Local". • When the TravelClock class inherits from the Clock class, it needs only to spell out these three differences. • Specification of class TravelClock follows. 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;};

  12. Calling the Base-Class Constructor • The constructor of a derived class has two tasks: • Initialize the base object. • Initialize all data members. • Frequently, a derived-class constructor must invoke the base-class constructor before initializing the derived-class data.

  13. Calling the Base-Class Constructor (cont.) • Here, we call the Clock constructor with the parameter mil 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.

  14. Calling the Base-Class Constructor (Syntax Constructor with Base-Class Initializer) • Constructor with Base-Class Initializer Derived_class_name::Derived_class_name(parameter list) :Base_class_name(expressions) { … statements inside the constructor … } • Example: Manager::Manager(string name, double salary, string dept) : Employee(name, salary) { department = dept; } • Purpose: Supply the implementation of a constructor, initializing the base class before the body of the derived-class constructor.

  15. Calling Base-Class Member Functions • Suppose B::f is a function in the base class. The the derived class D can take three kinds of actions. • The derived class can extendB::f by supplying a new implementation that refers to the base-class implementation. • For example, the TravelClock::get_hours function is an extension of Clock::get_hours. • The derived class can replaceB::f by supplying a new implementation that is unrelated to the base-class implementation. • For example, TravelClock::get_location is a replacement for Clock::get_location. • The derived class can inheritB::f by not supplying an implementation for f. • For example, TravelClock inherits Clock::get_minutes and Clock::is_military.

  16. Calling Base-Class Member Functions • A member function called without a parameter is called through the implicit parameter object of the derived class. if (is_military()) //it uses military time return (h + time_difference) % 24; • When the base class and the derived class have a member function with the same name, you must be more specific which function you want to call. int TravelClock::get_hours() const { int h = Clock::get_hours(); . . . } • The following call would die in an infinite recursion. int TravelClock::get_hours() const { int h = get_hours(); . . . } calls base-class function calls itself!! Not correct in this case!!!

  17. Example: Specification and Implementation of class TravelClock 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;  };

  18. Implementation of class TravelClock 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;elsereturn h;     }  }

  19. Example of program using the TravelClock class … 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;  }

  20. Polymorphism • You will find that there is quite a bit of repetitive code in clocks2.cpp. • It would be nicer if all three clocks were collected in a vector, as attempted next: vector<Clock> clocks(3); clocks[0] = Clock(true); clocks[1] = TravelClock(true, "Rome", 9); clocks[2] = TravelClock(false, "Tokyo", -7); for (int i = 0; i < clocks.size(); i++) {   cout << clocks[i].get_location() << " time: "     << clocks[i].get_hours() << ":"     << setw(2) << setfill('0'     << clocks[i].get_minutes()     << setfill(' ') << "\n"; } • Unfortunately, this does not work as expected. The output of this program is: Local time is 21:15  Local time is 21:15  Local time is 21:15 This is valid since every object of type TravelClock is also of type Clock

  21. Polymorphism • The compiler realizes that a TravelClock is a special case of a Clock, and permits the assignment clocks[1] = TravelClock(true, "Rome", 9); • 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 base-class variable. • The following figure illustrates the area that is copied with the previous statement. This portion of a TravelClock is copied to the Clock object in the previous assignment statement.

  22. Polymorphism (cont.) • A base-class pointer can point to a derived class object. (The reverse is an error). • By creating a vector of pointers to the base-class type, we can hold a collection of both base-class and derived-class objects. vector<Clock*> clocks(3); // populate clocks clocks[0] = new Clock(true); clocks[1] = new TravelClock(true, "Rome", 9); clocks[2] = new TravelClock(false, "Tokyo", -7); • Pointers to the various clock objects all have the same size - the size of a memory address - even though the objects themselves may have different sizes. • Since every TravelClock is a special case of a Clock, the starting address of a TravelClock object is the starting address of a Clock object.

  23. Polimorphisms (cont.) A pointer to Clock is also a valid pointer to objects of type TravelClock. This figure illustrates the memory organization after the three assignment statements in the code.

  24. Polymorphism • Unfortunately, the following code does not work either! cout << clocks[i]->get_location() << " time: " << clocks[i]->get_hours() << ":" << setw(2) << setfill('0') << clocks[i]->get_minutes() << setfill(' ') << "\n"; • The output is still: Local time is 21:15 Local time is 21:15 Local time is 9:15 • The reason is that both, Clock and TravelClock, have a get_location and a get_hours member function. • The compiler calls the Clock member function because the pointer is of type Clock*. But the correct result should be: Local time: 11:53 Rome time: 20:53 Tokyo time: 4:53

  25. Polymorphism (cont.) • You must alert the compiler that the function call needs to be preceded by the appropriate function selection, which can be a different one for every iteration in the loop. • Such a selection/call combination is called dynamic binding. • The traditional call, which always invokes the same function, is called static binding. • To tell the C++ compiler that a particular function needs to be bound dynamically, the function must be tagged as virtual. 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 previous code works as expected.

  26. Polymorphism - 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.

More Related