A Complete Guide to Programming in C++ part 54 ppt

10 245 1
A Complete Guide to Programming in C++ part 54 ppt

Đang tải... (xem toàn văn)

Thông tin tài liệu

REDEFINING MEMBERS ■ 509 ᮀ 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 public section 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. 510 ■ CHAPTER 23 INHERITANCE // 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 } ■ CONSTRUCTING AND DESTROYING DERIVED CLASSES First version of the constructor of PassCar Second version with base class initializer Third version with base class and member initializer CONSTRUCTING AND DESTROYING DERIVED CLASSES ■ 511 ᮀ 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 constructor. 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 PassCar contains 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 destructor need not be called explicitly as it is executed implicitly. 512 ■ CHAPTER 23 INHERITANCE // 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; } ■ OBJECTS OF DERIVED CLASSES 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 OBJECTS OF DERIVED CLASSES ■ 513 ᮀ Declaring Objects The program opposite illustrates how objects of derived classes can be used. Two objects, beetle and cabrio, of the derived class PassCar type are declared. As the PassCar class does not contain a default constructor, both objects must be initialized. However, it is sufficient to state a PassCar type with or without a sunroof as default values exist for all other data members. The object beetle is declared as const just to show that the get methods 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 PassCar class the method display() has been rede- fined. The statement Example: cabrio.display(); also outputs the additional data members passCarType and sunRoof. However, in the case of the van object in the Car class, 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 cabrio object, 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. 514 ■ CHAPTER 23 INHERITANCE // 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 } }; ■ PROTECTED MEMBERS Sample classes PROTECTED MEMBERS ■ 515 ᮀ 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 friend functions 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- vate member. That means, a protected member is inaccessible for base class objects and any classes derived from the base class. However, in contrast to a private member, methods and friend functions of derived classes can access the member. The classes defined opposite, Safe and Castle, show that protected members 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 Protected declarations should be used with caution. If you change the declaration of a protected member, every class derived from this class must be examined to ascertain whether additional modifications are necessary. exercises 516 ■ CHAPTER 23 INHERITANCE 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; ■ EXERCISES For exercise 1 Class Truck being derived from class Car EXERCISES ■ 517 Exercise 1 The classes Car and PassCar are to modify to allow objects to be created and destroyed. In addition, the class Truck is to be added to the class hierarchy. ■ Change the classes Car and PassCar to make the constructor issue the following message: "Creating an object of type ." ■ Define a destructor for the Car and PassCar classes.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 Truck class—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 Truck type object in your main function. If required by the user, enable your program to create and dis- play objects of the types PassCar and Car. Observe how the various objects and member objects are created and destroyed. Exercise 2 Derive two classes, DepAcc and SavAcc, from the Account class, 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 DepAcc class. The SavAcc contains 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 DepAcc and SavAcc types in the object declarations and outputting them.Then modify both a savings and a deposit account interactively and display the new values. 518 ■ CHAPTER 23 INHERITANCE Product PrepackedFood FreshFood 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 . 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. ᮀ. 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. The statement Example: cabrio.display(); also outputs the additional data members passCarType and sunRoof. However, in the case of the van object in the Car class, calling Example: van.display(); will

Ngày đăng: 06/07/2014, 17:21

Từ khóa liên quan

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan