Download presentation
Presentation is loading. Please wait.
Published byMuriel Harper Modified over 9 years ago
1
1 Chapter 11: Inheritance Chapter Goals To understand the concepts of inheritance and polymorphismTo understand the concepts of inheritance and polymorphism To learn how inheritance is a tool for code reuseTo learn how inheritance is a tool for code reuse To learn how to call base-class constructors and member functionsTo learn how to call base-class constructors and member functions To understand the difference between static and dynamic bindingTo understand the difference between static and dynamic binding To be able to implement dynamic binding with virtual functionsTo be able to implement dynamic binding with virtual functions
2
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 …new member functionsprivate: …new data members …new data members}; Class Manager is derived, Employee is base class.
3
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
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); Manager(string name, double salary, string dept); string get_department() const; string get_department() const;private: string department; string department;};
5
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
6 Example - Base Class : Clock #ifndef __CLOCK_H_ #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); #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 current location string get_location() const; // returns the hours in military format int get_hours() const; // returns the minutes // returns the minutes int get_minutes() const; // returns true if military format int get_minutes() const; // returns true if military format bool is_military() const; private: bool military; }; #endif bool is_military() const; private: bool military; }; #endif
7
7 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; }
8
8 Example of Program Using Class Clock #include #include #include 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; }
9
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
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_location() << " is " << clock.get_hours() << ":" << clock.get_hours() << ":" << clock.get_minutes(); << clock.get_minutes();
11
11 Derived Class (cont.) A TravelClock differs from a Clock in three ways: Its objects store the location and time difference.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_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".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
12 Calling the Base-Class Constructor The constructor of a derived class has two tasks: Initialize the base object.Initialize the base object. Initialize all data members.Initialize all data members. Frequently, a derived-class constructor must invoke the base-class constructor before initializing the derived-class data.
13
13 Calling the Base-Class Constructor (cont.) Here, we call the Clock constructor with the parameter 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.
14
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 … … statements inside the constructor …} Example: Manager::Manager(string name, double salary, Manager::Manager(string name, double salary, string dept) string dept) : Employee(name, salary) : 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
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 extend B::f by supplying a new implementation that refers to the base-class implementation.The derived class can extend B::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 replace B::f by supplying a new implementation that is unrelated to the base-class implementation.The derived class can replace B::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 inherit B::f by not supplying an implementation for f.The derived class can inherit B::f by not supplying an implementation for f. For example, TravelClock inherits Clock::get_minutes and Clock::is_military.
16
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; 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 TravelClock::get_hours() const { int h = Clock::get_hours(); int h = Clock::get_hours();...... } 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-class function calls itself!! Not correct in this case!!!
17
17 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
18
18 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
19
19 … 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
20
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 clocks(3); clocks[0] = Clock(true); clocks[1] = TravelClock(true, "Rome", 9); clocks[2] = TravelClock(false, "Tokyo", -7); vector 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"; } 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 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
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); 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
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 clocks(3); vector 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 - 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
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
24 Polymorphism Unfortunately, the following code does not work either! cout get_location() << " time: " get_hours() get_hours() << ":" << setw(2) << setfill('0') get_minutes() get_minutes() << setfill(' ') << "\n"; The output is still: 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
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
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.
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.