Constructors and Destructors in Derived Classes

As we explained in the preceding section, instantiating a derived-class object begins a chain of constructor calls in which the derived-class constructor, before performing its own tasks, invokes its direct base class's constructor either explicitly (via a base-class member initializer) or implicitly (calling the base class's default constructor). Similarly, if the base class is derived from another class, the base-class constructor is required to invoke the constructor of the next class up in the hierarchy, and so on. The last constructor called in this chain is the constructor of the class at the base of the hierarchy, whose body actually finishes executing first. The original derived-class constructor's body finishes executing last. Each base-class constructor initializes the base-class data members that the derived-class object inherits. For example, consider the CommissionEmployee/BasePlusCommissionEmployee hierarchy from Figs. 12.1712.20. When a program creates an object of class BasePlusCommissionEmployee, the CommissionEmployee constructor is called. Since class CommissionEmployee is at the base of the hierarchy, its constructor executes, initializing the private data members of CommissionEmployee that are part of the BasePlusCommissionEmployee object. When CommissionEmployee's constructor completes execution, it returns control to BasePlusCommissionEmployee's constructor, which initializes the BasePlusCommissionEmployee object's baseSalary.

Software Engineering Observation 12.7

When a program creates a derived-class object, the derived-class constructor immediately calls the base-class constructor, the base-class constructor's body executes, then the derived class's member initializers execute and finally the derived-class constructor's body executes. This process cascades up the hierarchy if the hierarchy contains more than two levels.

When a derived-class object is destroyed, the program calls that object's destructor. This begins a chain (or cascade) of destructor calls in which the derived-class destructor and the destructors of the direct and indirect base classes and the classes' members execute in reverse of the order in which the constructors executed. When a derived-class object's destructor is called, the destructor performs its task, then invokes the destructor of the next base class up the hierarchy. This process repeats until the destructor of the final base class at the top of the hierarchy is called. Then the object is removed from memory.

Software Engineering Observation 12.8

Suppose that we create an object of a derived class where both the base class and the derived class contain objects of other classes. When an object of that derived class is created, first the constructors for the base class's member objects execute, then the base-class constructor executes, then the constructors for the derived class's member objects execute, then the derived class's constructor executes. Destructors for derived-class objects are called in the reverse of the order in which their corresponding constructors are called.


Base-class constructors, destructors and overloaded assignment operators (see Chapter 11, Operator Overloading; String and Array Objects) are not inherited by derived classes. Derived-class constructors, destructors and overloaded assignment operators, however, can call base-class constructors, destructors and overloaded assignment operators.

Our next example revisits the commission employee hierarchy by defining class CommissionEmployee (Figs. 12.2212.23) and class BasePlusCommissionEmployee (Figs. 12.2412.25) that contain constructors and destructors, each of which prints a message when it is invoked. As you will see in the output in Fig. 12.26, these messages demonstrate the order in which the constructors and destructors are called for objects in an inheritance hierarchy.

Figure 12.22. CommissionEmployee class header file.

 1 // Fig. 12.22: CommissionEmployee.h
 2 // CommissionEmployee class definition represents a commission employee.
 3 #ifndef COMMISSION_H
 4 #define COMMISSION_H
 5
 6 #include  // C++ standard string class
 7 using std::string;
 8
 9 class CommissionEmployee
10 {
11 public:
12 CommissionEmployee( const string &, const string &, const string &,
13 double = 0.0, double = 0.0 );
14 ~CommissionEmployee(); // destructor
15
16 void setFirstName( const string & ); // set first name
17 string getFirstName() const; // return first name
18
19 void setLastName( const string & ); // set last name
20 string getLastName() const; // return last name
21
22 void setSocialSecurityNumber( const string & ); // set SSN
23 string getSocialSecurityNumber() const; // return SSN
24
25 void setGrossSales( double ); // set gross sales amount
26 double getGrossSales() const; // return gross sales amount
27
28 void setCommissionRate( double ); // set commission rate
29 double getCommissionRate() const; // return commission rate
30
31 double earnings() const; // calculate earnings
32 void print() const; // print CommissionEmployee object
33 private:
34 string firstName;
35 string lastName;
36 string socialSecurityNumber;
37 double grossSales; // gross weekly sales
38 double commissionRate; // commission percentage
39 }; // end class CommissionEmployee
40
41 #endif

Figure 12.23. CommissionEmployee's constructor outputs text.

(This item is displayed on pages 672 - 674 in the print version)

 1 // Fig. 12.23: CommissionEmployee.cpp
 2 // Class CommissionEmployee member-function definitions.
 3 #include 
 4 using std::cout;
 5 using std::endl;
 6
 7 #include "CommissionEmployee.h"  // CommissionEmployee class definition
 8
 9 // constructor
10 CommissionEmployee::CommissionEmployee(
11 const string &first, const string &last, const string &ssn,
12 double sales, double rate )
13 : firstName( first ), lastName( last ), socialSecurityNumber( ssn )
14 {
15 setGrossSales( sales ); // validate and store gross sales
16 setCommissionRate( rate ); // validate and store commission rate
17
18 cout << "CommissionEmployee constructor: " << endl;
19 print();
20 cout << "

";
21 } // end CommissionEmployee constructor
22
23 // destructor 
24 CommissionEmployee::~CommissionEmployee() 
25 { 
26  cout << "CommissionEmployee destructor: " << endl;
27  print(); 
28  cout << "

"; 
29 } // end CommissionEmployee destructor 
30
31 // set first name
32 void CommissionEmployee::setFirstName( const string &first )
33 {
34 firstName = first; // should validate
35 } // end function setFirstName
36
37 // return first name
38 string CommissionEmployee::getFirstName() const
39 {
40 return firstName;
41 } // end function getFirstName
42
43 // set last name
44 void CommissionEmployee::setLastName( const string &last )
45 {
46 lastName = last; // should validate
47 } // end function setLastName
48
49 // return last name
50 string CommissionEmployee::getLastName() const
51 {
52 return lastName;
53 } // end function getLastName
54
55 // set social security number
56 void CommissionEmployee::setSocialSecurityNumber( const string &ssn )
57 {
58 socialSecurityNumber = ssn; // should validate
59 } // end function setSocialSecurityNumber
60
61 // return social security number
62 string CommissionEmployee::getSocialSecurityNumber() const
63 {
64 return socialSecurityNumber;
65 } // end function getSocialSecurityNumber
66
67 // set gross sales amount
68 void CommissionEmployee::setGrossSales( double sales )
69 {
70 grossSales = ( sales < 0.0 ) ? 0.0 : sales;
71 } // end function setGrossSales
72
73 // return gross sales amount
74 double CommissionEmployee::getGrossSales() const
75 {
76 return grossSales;
77 } // end function getGrossSales
78
79 // set commission rate
80 void CommissionEmployee::setCommissionRate( double rate )
81 {
82 commissionRate = ( rate > 0.0 && rate < 1.0 ) ? rate : 0.0;
83 } // end function setCommissionRate
84
85 // return commission rate
86 double CommissionEmployee::getCommissionRate() const
87 {
88 return commissionRate;
89 } // end function getCommissionRate
90
91 // calculate earnings
92 double CommissionEmployee::earnings() const
93 {
94 return getCommissionRate() * getGrossSales();
95 }  // end function earnings
96
97 // print CommissionEmployee object
98 void CommissionEmployee::print() const
99 {
100 cout << "commission employee: "
101 << getFirstName() << ' ' << getLastName()
102 << "
social security number: " << getSocialSecurityNumber()
103 << "
gross sales: " << getGrossSales()
104 << "
commission rate: " << getCommissionRate();
105 } // end function print

Figure 12.24. BasePlusCommissionEmployee class header file.

(This item is displayed on page 674 in the print version)

 1 // Fig. 12.24: BasePlusCommissionEmployee.h
 2 // BasePlusCommissionEmployee class derived from class
 3 // CommissionEmployee.
 4 #ifndef BASEPLUS_H
 5 #define BASEPLUS_H
 6
 7 #include  // C++ standard string class
 8 using std::string;
 9
10 #include "CommissionEmployee.h" // CommissionEmployee class declaration
11
12 class BasePlusCommissionEmployee : public CommissionEmployee
13 {
14 public:
15 BasePlusCommissionEmployee( const string &, const string &,
16 const string &, double = 0.0, double = 0.0, double = 0.0 );
17 ~BasePlusCommissionEmployee(); // destructor
18
19 void setBaseSalary( double ); // set base salary
20 double getBaseSalary() const; // return base salary
21
22 double earnings() const; // calculate earnings
23 void print() const; // print BasePlusCommissionEmployee object
24 private:
25 double baseSalary; // base salary
26 }; // end class BasePlusCommissionEmployee
27
28 #endif

In this example, we modified the CommissionEmployee constructor (lines 1021 of Fig. 12.23) and included a CommissionEmployee destructor (lines 2429), each of which outputs a line of text upon its invocation. We also modified the BasePlusCommissionEmployee constructor (lines 1122 of Fig. 12.25) and included a BasePlusCommissionEmployee destructor (lines 2530), each of which outputs a line of text upon its invocation.


Figure 12.25. BasePlusCommissionEmployee's constructor outputs text.

(This item is displayed on pages 674 - 675 in the print version)

 1 // Fig. 12.25: BasePlusCommissionEmployee.cpp
 2 // Class BasePlusCommissionEmployee member-function definitions.
 3 #include 
 4 using std::cout;
 5 using std::endl;
 6
 7 // BasePlusCommissionEmployee class definition
 8 #include "BasePlusCommissionEmployee.h"
 9
10 // constructor
11 BasePlusCommissionEmployee::BasePlusCommissionEmployee(
12 const string &first, const string &last, const string &ssn,
13 double sales, double rate, double salary )
14 // explicitly call base-class constructor
15 : CommissionEmployee( first, last, ssn, sales, rate )
16 {
17 setBaseSalary( salary ); // validate and store base salary
18
19 cout << "BasePlusCommissionEmployee constructor: " << endl;
20 print();
21 cout << "

";
22 } // end BasePlusCommissionEmployee constructor
23
24 // destructor 
25 BasePlusCommissionEmployee::~BasePlusCommissionEmployee() 
26 { 
27  cout << "BasePlusCommissionEmployee destructor: " << endl;
28  print(); 
29  cout << "

"; 
30 } // end BasePlusCommissionEmployee destructor 
31
32 // set base salary
33 void BasePlusCommissionEmployee::setBaseSalary( double salary )
34 {
35 baseSalary = ( salary < 0.0 ) ? 0.0 : salary;
36 } // end function setBaseSalary
37
38 // return base salary
39 double BasePlusCommissionEmployee::getBaseSalary() const
40 {
41 return baseSalary;
42 } // end function getBaseSalary
43
44 // calculate earnings
45 double BasePlusCommissionEmployee::earnings() const
46 {
47 return getBaseSalary() + CommissionEmployee::earnings();
48 } // end function earnings
49
50 // print BasePlusCommissionEmployee object
51 void BasePlusCommissionEmployee::print() const
52 {
53 cout << "base-salaried ";
54
55 // invoke CommissionEmployee's print function
56 CommissionEmployee::print();
57
58 cout << "
base salary: " << getBaseSalary();
59 } // end function print

Figure 12.26 demonstrates the order in which constructors and destructors are called for objects of classes that are part of an inheritance hierarchy. Function main (lines 1534) begins by instantiating CommissionEmployee object employee1 (lines 2122) in a separate block inside main (lines 2023). The object goes in and out of scope immediately (the end of the block is reached as soon as the object is created), so both the CommissionEmployee constructor and destructor are called. Next, lines 2627 instantiate BasePlusCommissionEmployee object employee2. This invokes the CommissionEmployee constructor to display outputs with values passed from the BasePlusCommissionEmployee constructor, then the output specified in the BasePlusCommissionEmployee constructor is performed. Lines 3031 then instantiate BasePlusCommissionEmployee object employee3. Again, the CommissionEmployee and BasePlusCommissionEmployee constructors are both called. Note that, in each case, the body of the CommissionEmployee constructor is executed before the body of the BasePlusCommissionEmployee constructor executes. When the end of main is reached, the destructors are called for objects employee2 and employee3. But, because destructors are called in the reverse order of their corresponding constructors, the BasePlusCommissionEmployee destructor and CommissionEmployee destructor are called (in that order) for object employee3, then the BasePlusCommissionEmployee and CommissionEmployee destructors are called (in that order) for object employee2.

Figure 12.26. Constructor and destructor call order.

(This item is displayed on pages 676 - 678 in the print version)

 1 // Fig. 12.26: fig12_26.cpp
 2 // Display order in which base-class and derived-class constructors
 3 // and destructors are called.
 4 #include 
 5 using std::cout;
 6 using std::endl;
 7 using std::fixed;
 8
 9 #include 
10 using std::setprecision;
11
12 // BasePlusCommissionEmployee class definition
13 #include "BasePlusCommissionEmployee.h"
14
15 int main()
16 {
17 // set floating-point output formatting
18 cout << fixed << setprecision( 2 );
19
20 { // begin new scope 
21  CommissionEmployee employee1( 
22  "Bob", "Lewis", "333-33-3333", 5000, .04 );
23 } // end scope 
24
25 cout << endl;
26 BasePlusCommissionEmployee 
27  employee2( "Lisa", "Jones", "555-55-5555", 2000, .06, 800 );
28
29 cout << endl;
30 BasePlusCommissionEmployee 
31  employee3( "Mark", "Sands", "888-88-8888", 8000, .15, 2000 );
32 cout << endl;
33 return 0;
34 } // end main
 
 CommissionEmployee constructor:
 commission employee: Bob Lewis
 social security number: 333-33-3333
 gross sales: 5000.00
 commission rate: 0.04

 CommissionEmployee destructor:
 commission employee: Bob Lewis
 social security number: 333-33-3333
 gross sales: 5000.00
 commission rate: 0.04


 CommissionEmployee constructor:
 base-salaried commission employee: Lisa Jones
 social security number: 555-55-5555
 gross sales: 2000.00
 commission rate: 0.06

 BasePlusCommissionEmployee constructor:
 base-salaried commission employee: Lisa Jones
 social security number: 555-55-5555
 gross sales: 2000.00
 commission rate: 0.06
 base salary: 800.00


 CommissionEmployee constructor:
 commission employee: Mark Sands
 social security number: 888-88-8888
 gross sales: 8000.00
 commission rate: 0.15

 BasePlusCommissionEmployee constructor:
 base-salaried commission employee: Mark Sands
 social security number: 888-88-8888
 gross sales: 8000.00
 commission rate: 0.15
 base salary: 2000.00

 BasePlusCommissionEmployee destructor:
 base-salaried commission employee: Mark Sands
 social security number: 888-88-8888
 gross sales: 8000.00
 commission rate: 0.15
 base salary: 2000.00


 CommissionEmployee destructor:
 commission employee: Mark Sands
 social security number: 888-88-8888
 gross sales: 8000.00
 commission rate: 0.15

 BasePlusCommissionEmployee destructor:
 base-salaried commission employee: Lisa Jones
 social security number: 555-55-5555
 gross sales: 2000.00
 commission rate: 0.06
 base salary: 800.00

 CommissionEmployee destructor:
 commission employee: Lisa Jones
 social security number: 555-55-5555
 gross sales: 2000.00
 commission rate: 0.06
 

Introduction to Computers, the Internet and World Wide Web

Introduction to C++ Programming

Introduction to Classes and Objects

Control Statements: Part 1

Control Statements: Part 2

Functions and an Introduction to Recursion

Arrays and Vectors

Pointers and Pointer-Based Strings

Classes: A Deeper Look, Part 1

Classes: A Deeper Look, Part 2

Operator Overloading; String and Array Objects

Object-Oriented Programming: Inheritance

Object-Oriented Programming: Polymorphism

Templates

Stream Input/Output

Exception Handling

File Processing

Class string and String Stream Processing

Web Programming

Searching and Sorting

Data Structures

Bits, Characters, C-Strings and structs

Standard Template Library (STL)

Other Topics

Appendix A. Operator Precedence and Associativity Chart

Appendix B. ASCII Character Set

Appendix C. Fundamental Types

Appendix D. Number Systems

Appendix E. C Legacy Code Topics

Appendix F. Preprocessor

Appendix G. ATM Case Study Code

Appendix H. UML 2: Additional Diagram Types

Appendix I. C++ Internet and Web Resources

Appendix J. Introduction to XHTML

Appendix K. XHTML Special Characters

Appendix L. Using the Visual Studio .NET Debugger

Appendix M. Using the GNU C++ Debugger

Bibliography



C++ How to Program
C++ How to Program (5th Edition)
ISBN: 0131857576
EAN: 2147483647
Year: 2004
Pages: 627

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net