Of course, you can overload methods within the same class, and this means you can repeatedly redefine a base class method for a derived class.. 䊐 Access to the Members in the Base Class
Trang 1䊐 Redefinition
There are two options for the names of data members or methods in derived classes:
1 The name does not occur in the base class →no redefinition
2 The name already exists in the base class →redefinition
In the second case, the member of the same name continues to exist unchanged in the base class In other words, redefining members in a derived class has no effect on the base class
However, the name lookup rules for the compiler lead to the following scenario:
■ if a member is redefined in a derived class, it will mask the corresponding mem-ber in the base class
This situation is similar to the one seen for local and global variables A local variable will mask a previously defined global variable with the same name
䊐 Redefinition and Overloading
Normally, methods are redefined in derived classes This adopts the methods to the new
features of the class When a method is redefined, the signature and the return type of the method can be changed However, a redefinition does not overload functions since the derived class has a different scope
Redefining a method will always mask a method with the same name in the base class
Of course, you can overload methods within the same class, and this means you can repeatedly redefine a base class method for a derived class
䊐 Access to the Members in the Base Class
If you redefine a method in a derived class, this does not alter the fact that the base class method still exists If the method was declared in the publicsection of the base class, you can call it to redefine a method The range ::operator is used to access the base class method
The new version of the display() method opposite illustrates this point The
display()method defined in the base class is used to output the data members of the base class To do so, you must use the range operator with the name of the base class Otherwise the display()method in the derived class will call itself and head off into
an indefinite recursion
Trang 2510 C H A P T E R 2 3 I N H E R I T A N C E
// First version of the constructor of PassCar //
-PassCar::PassCar(const string& tp, bool sr, int n,
const string& hs)
{ setNr(n); // Initial values for data setProd(hs); // members of the base class passCarType = tp; // Initial values for data mem-sunRoof = sr; // bers of the derived class }
// Second version of the constructors of PassCar //
-PassCar::PassCar(const string& tp, bool sr, int n,
const string& hs) : Car( n, hs)
{ passCarType = tp; // Initial values for data mem-sunRoof = sr; // bers of the derived class }
// Third version of the constructor of PassCar //
-PassCar::PassCar(const string& tp, bool sr, int n,
const string& hs) : Car( n, hs), passCarType( tp ), sunRoof( sr )
{ // There remains nothing to do }
First version of the constructor of PassCar
Second version with base class initializer
Third version with base class and member initializer
Trang 3䊐 Constructor Calls
The constructor of a derived class is required to create an object of the derived class type
As the derived class contains all the members of the base class, the base sub-object must also be created and initialized The base class constructor is called to perform this task Unless otherwise defined, this will be the default constructor
The order in which the constructors are called is important The base class construc-tor is called first, then the derived class construcconstruc-tor The object is thus constructed from its core outwards
The first version of the constructor for PassCar, as shown opposite, sets initial val-ues by calling the access methods of the base class An implicit call to the default con-structor of the base class occurs prior to this, and the base sub-object is initialized with default values This process has the same drawbacks as the technique of creating objects with member objects A default constructor must be available in the base class and ini-tialization with incorrect values before assigning live values impacts the response of the program
䊐 Base Initializer
If the base class contains a constructor with parameters, it makes sense to call this
con-structor This immediately initializes the data members with correct values A base initial-izer for the constructor of the derived class can be defined for this purpose.
The second version of the constructor for PassCarcontains a base initializer
Example: Car( n, hs )
The syntax of the base initializer for base sub-objects is similar to that of the member ini-tializer for member sub-objects This means that you can state both the base and the member initializer in a list separated by commas The third version of the PassCar con-structor illustrates this point
䊐 Destroying Objects
When an object is destroyed, the destructor of the derived class is first called, followed by the destructor of the base class The reverse order of the constructor calls applies You need to define a destructor for a derived class if actions performed by the con-structor need to be reversed The base class decon-structor need not be called explicitly as it
is executed implicitly
Trang 4512 C H A P T E R 2 3 I N H E R I T A N C E
// car_t.cpp: Testing the base class Car and // the derived class PassCar
//
-#include "car.h"
int main() {
const PassCar beetle("Beetle", false, 3421, "VW");
beetle.display(); cout << "\nAnd the passenger car number again: "
<< beetle.getNr() << endl;
PassCar cabrio("Carrera", true);
cabrio.setNr(1000);
cabrio.setProd("Porsche");
cabrio.display();
cout << "\nOnly data of the base class: ";
cabrio.Car::display();
return 0;
}
Sample program
Screen output
-Car number: 3421
Producer: VW Type: Beetle Sunroof: no
And the passenger car number again: 3421
-Car number: 1000
Producer: Porsche Type: Carrera Sunroof: yes
Only data of the base class:
-Car number: 1000
Producer: Porsche
Trang 5䊐 Declaring Objects
The program opposite illustrates how objects of derived classes can be used Two objects,
beetleandcabrio, of the derived class PassCartype are declared As the PassCar
class does not contain a default constructor, both objects must be initialized However, it
is sufficient to state a PassCartype with or without a sunroof as default values exist for all other data members
The object beetleis declared as constjust to show that the getmethods and the
display()method can also be called for constant objects since they were declared as read-only methods
However, the following call is invalid:
Example: beetle.setNr( 7564 ); // Error
This means you have to correctly define all the initial values for the object when you declare it
䊐 Calling Redefined Methods
When you call a redefined method, the object type determines what version of the method will be executed In the PassCarclass the method display()has been rede-fined The statement
Example: cabrio.display();
also outputs the additional data members passCarType andsunRoof However, in the case of the vanobject in the Carclass, calling
Example: van.display();
will execute the method in the base class
䊐 Calling Methods in the Base Class
You may be wondering if a base class method can be called for an object of a derived class, if the method has been redefined in the derived class This is possible using the scope resolution operator,::
If you want to display the basic data of the cabrioobject, you can use a direct call to the base class method display()to do so
Example: cabrio.Car::display();
The name of the method is preceded by the name of the base class and the scope resolu-tion operator in this case
Trang 6514 C H A P T E R 2 3 I N H E R I T A N C E
// safe.h : The classes Safe and Castle //
-#include <iostream>
using namespace std;
class Safe
{
private:
int topSecret;
protected:
int secret;
void setTopSecret( int n) { topSecret = n;}
int getTopSecret() const { return topSecret;} void setSecret( int n){ secret = n;}
int getSecret() const { return secret;}
public:
int noSecret;
Safe() { topSecret = 100; secret = 10; noSecret = 0; } };
class Castle : public Safe
{
public:
Castle() {
// topSecret = 10; // Error, because private setTopSecret(10); // ok, because protected secret = 1; // ok, because protected noSecret = 0; // ok, because public }
void test() {
// top.Secret = 200; // Error, because private setTopSecret(200); // ok, because protected secret = 20; // ok, because protected noSecret = 2; // ok, because public }
};
Sample classes
Trang 7䊐 Access to Sheltered Members
The private members of a base class are equally inaccessible for the methods and friend
functions of a derived class
When you create a class hierarchy you may want require the methods and friend
functions of a derived class to communicate directly with the members of the base class This would be particularly necessary if the base class contained members for use as build-ing blocks for derived classes but not for general purpose use
For example, a class used to represent a window on screen could contain the dimen-sions and other characteristics of a general windows The characteristics need protecting; however, methods in derived classes will still need direct access
䊐 Protected Members
To allow methods and friendfunctions access to the sheltered members of a base class, let’s introduce an additional level of access control between private and public
This is achieved by means of protected declarations.
A member declared protected is sheltered from external access just like a pri-vatemember That means, a protectedmember is inaccessible for base class objects and any classes derived from the base class However, in contrast to a privatemember, methods and friendfunctions of derived classes can access the member
The classes defined opposite, SafeandCastle, show that protectedmembers of the base class can be accessed directly in a derived class In contrast to this, protected
members are inaccessible to users of these classes
Example: Castle treasure;
treasure.topSecret = 1; // Error: private
treasure.secret = 2; // Error: protected
treasure.setTopSecret(5); // Error: protected
treasure.noSecret = 10; // ok
Protecteddeclarations should be used with caution If you change the declaration of a
protectedmember, every class derived from this class must be examined to ascertain whether additional modifications are necessary
Trang 8516 C H A P T E R 2 3 I N H E R I T A N C E
Additional data members:
Type Number of axles int Load capacity double
Additional methods:
void setAxles( int a );
int getAxles() const;
void setCapacity( double cp ); void getCapacity() const;
void display() const;
For exercise 1
Class Truck being derived from class Car
Trang 9Exercise 1
The classes CarandPassCarare to modify to allow objects to be created and destroyed In addition, the class Truckis to be added to the class hierarchy
■ Change the classes CarandPassCarto make the constructor issue the following message:
"Creating an object of type "
■ Define a destructor for the CarandPassCarclasses.The destructor should issue the following message:
"Destroying an object of type "
■ Then define the class Truck, which is derived from Car, using the data members shown opposite, a constructor, a destructor, and the additional methods shown opposite
■ Implement the constructor for the Truckclass—the constructor should again issue a suitable message Use the base initializer to initialize the data members of Car
■ Define a destructor for Truck—the destructor should again issue a suit-able message for trucks
■ To test your class, create and display a Trucktype object in your main function If required by the user, enable your program to create and dis-play objects of the types PassCarandCar
Observe how the various objects and member objects are created and
destroyed
Exercise 2
Derive two classes,DepAccandSavAcc, from the Accountclass, which was defined in Chapter 14, in the section titled “Const Objects and Methods.”
Additionally define an overdraft limit and an interest rate for the DepAccclass TheSavAcccontains the members of the base class and an interest rate
■ For both classes, define constructors to provide default values for all parameters, add access methods, and add a display()method for screen output
■ Test the new classes by initializing objects of the DepAccandSavAcc types in the object declarations and outputting them.Then modify both a savings and a deposit account interactively and display the new values
Trang 10518 C H A P T E R 2 3 I N H E R I T A N C E
Product
Properties:
Barcode Name
Methods:
setCode() getCode() .
scanner() printer()
Properties:
Price per piece
Methods:
getPrice() setPrice() .
scanner() printer()
Properties:
Weight Price per pound
Methods:
setWght() getWght() .
scanner() printer()
Exercise 3