499 Inheritance This chapter describes how derived classes can be constructed from existing classes by inheritance. Besides defining derived classes, we will also discuss ■ how members are redefined ■ how objects are constructed and destroyed, and ■ how access control to base classes can be realized. chapter 23 500 ■ CHAPTER 23 INHERITANCE ■ CONCEPT OF INHERITANCE Is relation Car Properties and capacities of class Car Properties and capacities of class Car Properties and capacities of class Car Additional properties and capacities of class PassCar Additional properties and capacities of class Truck PassCar Truck CONCEPT OF INHERITANCE ■ 501 ᮀ Base Classes and Derived Classes Inheritance allows new classes to be constructed on the basis of existing classes. The new derived class “inherits” the data and methods of the so-called base class. But you can add more characteristics and functionality to the new class. A fleet management program used by a car hire company needs to handle all kinds of vehicles—automobiles, motorcycles, trucks, and so on. All of these vehicles have an identification number that indicates the vehicle, the manufacturer, and the vehicle sta- tus, such as “hired,” “repair shop,” and so on. Additionally, operations such as “modify status” are required for the class. To differentiate between vehicle types, various classes are derived from the base class Car, such as PassCar, which is used to represent passenger-carrying vehicles. This class has additional attributes, such as the number of seats, type, sunroof (yes/no), and various additional operations. ᮀ Is Relationship An object of the PassCar type is a special object of the Car class. A passenger vehicle is a special kind of car. In cases like this we can say that the derived class establishes an is relationship to the base class. We distinguish between this close relationship and a so-called has relationship. As already mentioned, a has relationship occurs between two classes when an member of one class has another class type. An Account object has a string object to represent the name of the account holder, for example. ᮀ Data Abstraction and Reusability Inheritance has a number of important benefits for software developers: ■ data abstraction: General characteristics and abilities can be handled by generic (base) classes and specializations can be organized in hierarchical relationships by means of derived classes. This makes it easier to manage complex situations and relationships. ■ re-usability: Classes that you have defined and tested can be reused and adapted to perform new tasks. The base class implementation need not be known for this purpose: only the public interfaces are required. 502 ■ CHAPTER 23 INHERITANCE B Base class B C D B is a direct base class B is an indirect base class class C : public B { private: // Declaration of additional private // data members and member functions public: // Declaration of additional public // data members and member functions }; ■ DERIVED CLASSES Defining a derived class Direct and indirect derivation DERIVED CLASSES ■ 503 When you define a derived class, the base class, the additional data members and meth- ods, and the access control to the base class are defined. The opposite page shows a schematic definition of a derived class, C. The C class inherits the B class, which is defined in the public section following the colon. The private and public sections contain additional members of the C class. ᮀ Access to Public Members in the Base Class Access privileges to the base class B are designated by the public keyword that pre- cedes the B. In other words, ■ all the public members in base class B are publicly available in the derived class C. This kind of inheritance ports the public interface of the base class to the derived class where it is extended by additional declarations. Thus, objects of the derived class can call the public methods of the base class. A public base class, therefore, imple- ments the is relationship; this is quite common. There are some less common cases where access to the members of the base class needs to be restricted or prohibited. Only the methods of class C can still access the public members of B, but not the users of that class. You can use private or pro- tected derivation to achieve this (these techniques will be discussed later). ᮀ Access to Private Members of the Base Class The private members of the base class are protected in all cases. That is, ■ the methods of the derived class cannot access the private members of the base class. Imagine the consequences if this were not so: you would be able to hack access to the base class by simply defining a derived class, thus undermining any protection offered by data encapsulation. ᮀ Direct and Indirect Base Classes The derived class C can itself be a base class for a further class, D. This allows for class hierarchies. Class B then becomes an indirect base class for class D. In the graphic on the opposite page, the arrow ↑ means directly derived from. That is, class D is a direct derivation of class C and an indirect derivation of B. 504 ■ CHAPTER 23 INHERITANCE // car.h: Definition of baseclass Car and // of the derived class PassCar // #include <iostream> #include <string> using namespace std; class Car // Base class { private: long nr; string producer; public: // Constructor: Car( long n = 0L, const string& prod = ""); // Access methods: long getNr(void) const { return nr; } void setNr( long n ) { nr = n; } const string& getProd() const{ return producer; } void setProd(const string& p){ producer = p; } void display( void ) const; // Display a car }; class PassCar : public Car // Derived class { private: string passCarType; bool sunRoof; public: // Constructor: PassCar( const string& tp, bool sd, int n = 0 , const string& h = ""); // Access methods: const string& getType() const{ return passCarType; } void setType( const string s) { passCarType = s; } bool getSunRoof() const { return sunRoof; } void setSunRoof( bool b ) { sunRoof = b; } void display() const; }; ■ MEMBERS OF DERIVED CLASSES Base class Car and derived class PassCar MEMBERS OF DERIVED CLASSES ■ 505 Let’s look at the example on the opposite page to illustrate how derived classes are defined. The Car class and a derived class PassCar are defined in the example. ᮀ Data Members and Methods The base class Car contains two data members, nr and producer, which are used to represent an identification number and the name of the manufacturer. The derived class PassCar inherits these data members. Thus, an object of the PassCar class also con- tains the data members nr and producer. The object includes a so-called base sub- object of type Car. The PassCar class additionally contains the data members passCarType and sunRoof to represent a passenger vehicle with or without a sunroof. So a PassCar type object has a total of four data members. For the sake of simplicity, we have omitted fur- ther data members, such as the number of seats, etc. The base class Car contains a constructor, access methods, and the method display(), which is used for screen output. The methods are also inherited by the derived class PassCar. In the PassCar class a constructor, additional access methods, and a second output function also called display() are declared. The derived class thus inherits a method called display() and declares a method with the same name. The display() method is said to have been redefined. Every member function and every data member in a derived class can be redefined. The member assumes a new meaning for the derived class. The member inherited from the base class is also available in the derived class and will retain its original meaning. We will be looking at this point in more detail later. ᮀ Public Interface Since the Car class is a public base class of the PassCar class, all the public mem- bers of the base class are available in the derived class. For example, you can call the getNr() method for an object named cabrio in the PassCar class. Example: cout << "Car number: "<< cabrio.getNr(); The public interface of the derived class thus comprises ■ the public members of the base class and ■ the public members additionally defined in the derived class. 506 ■ CHAPTER 23 INHERITANCE class Car class PassCar : public Car void PassCar::display( void) const private: private: public: public: << getNr(); << getProd(); cout << "Type: "<< passCarType; cout << "Type: "<< passCarTyp if( sunRoof) cout << "yes"; else cout << " no"; cout << endl; cout << "\nCar number: " string passCarType; long nr; string producer; long getNr(void); bool sunRoof; cout << "\nProducer: " } { { { } } . . . . . . . . . ok ok not ok ■ MEMBER ACCESS Accessing members of base class Car MEMBER ACCESS ■ 507 ᮀ Access to Additional Members The methods of derived classes can access any member additionally defined in the derived class. Example: const string& getType() const { return passCarType; } The getType() method directly accesses the private data member passCarType in the PassCar class in this example. ᮀ Access to Private Members of the Base Class However, a private member of the base class is not directly accessible for the methods of the derived class. The output function display() in the derived class PassCar, for example, cannot contain the following statement: Example: cout << "Producer: " << producer; As producer is a private data member of the base class Car, the compiler would issue an error message at this point. Methods belonging to derived classes only have indirect access to the private data members of the base class. They use access methods in the public declaration of the base class for this purpose. The opposite page shows a version of the display() method that calls the get methods in its base class Car. When you call an access method, you do not need to state the method’s base class. The base class is identified by the this pointer, which is passed implicitly as an argu- ment. The call to getProd() on the opposite page is thus equivalent to: Example: this->getProd(); ᮀ Name Lookup The following rules apply when searching for the name of a method: ■ the compiler looks for the name of the method called in the derived class first ■ if the name cannot be found, the compiler walks one step up the tree and looks for a public method with that name. The above example thus calls the getProd() in the base class Car, as the method is not defined in the PassCar class. 508 ■ CHAPTER 23 INHERITANCE // Within file Car.cpp // This version of method PassCar::display() calls // the method display() of the base class. // void PassCar::display( void) const { Car::display(); // Method in base class cout << "Type: " << passCarType; cout << "\nSunroof: "; if(sunRoof) cout << "yes "<< endl; else cout << "no " << endl; } ■ REDEFINING MEMBERS New version of method display() . from the base class is also available in the derived class and will retain its original meaning. We will be looking at this point in more detail later. ᮀ Public Interface Since the Car class is a public. capacities of class Car Properties and capacities of class Car Properties and capacities of class Car Additional properties and capacities of class PassCar Additional properties and capacities of class Truck PassCar. data and methods of the so-called base class. But you can add more characteristics and functionality to the new class. A fleet management program used by a car hire company needs to handle all