| My Training Period: xx hours
This is a continuation from previous Module and a final part. The source code for this tutorial is available in C++ Inheritance source codes.
The C++ Inheritance programming abilities: Able to understand and use:
15.7 The Constructor Execution Order
// sedan_car.initialize(4, 3500.0, 5);
truck trailer;
// trailer.initialize(18, 12500.0); // trailer.init_truck(1, 33675.0);
|
As the objects go out of scope, they must have their destructors executed also, and since we didn't define any, the default destructors will be executed.
Once again, the destruction of the base class object named unicycle is no problem, its destructor is executed and the object is gone.
The sedan_car object however, must have two destructors executed to destroy each of its parts, the base class part and the derived class part. The destructors for this object are executed in reverse order from the order in which they were constructed.
In other words, the object is dismantled in the opposite order from the order in which it was assembled. The derived class destructor is executed first, then the base class destructor and the object is removed from the allocation.
Remember that every time an object is instantiated, every portion of it must have a constructor executed on it. Every object must also have a destructor executed on each of its parts when it is destroyed in order to properly dismantle the object and free up the allocation. Compile and run this program.
Examine the program example named inherit5.cpp for another variation to our basic program, this time using constructors that are more than just the default constructors. You will notice that each class has another constructor declared within it.
1. // program inherit5.cpp
2. #include <iostream>
3. using namespace std;
4.
5. // base and derived class declaration part
6. class vehicle
7. {
8. protected:
9. int wheels;
10. double weight;
11. public:
12. vehicle(void)
13. {
14. wheels = 7; weight = 11111.0;
15. cout<<"It is me!, Constructor #1, own by base class"<<'\n';
16. }
17.
18. vehicle(int input_wheels, double input_weight)
19. {
20. wheels = input_wheels; weight = input_weight;
21. cout<<"It is me!, Constructor #2, own by base class"<<'\n';
22. }
23.
24. void initialize(int input_wheels, double input_weight);
25. int get_wheels(void) {return wheels;}
26. double get_weight(void) {return weight;}
27. double wheel_load(void) {return (weight/wheels);}
28. };
29.
30. class car : public vehicle
31. {
32. int passenger_load;
33. public:
34. car(void)
35. {
36. passenger_load = 4; cout<<"It is me!, Constructor #3, derived class,
37. car"<<'\n';
38. }
39.
40. car(int people, int input_wheels, double input_weight):vehicle(input_wheels,
41. input_weight), passenger_load(people)
42. {
43. cout<<"It is me!, Constructor #4, derived class, car"<<'\n';
44. }
45.
46. void initialize(int input_wheels, double input_weight, int people = 4);
47. int passengers(void) {return passenger_load;}
48. };
49.
50. class truck : public vehicle
51. {
52. int passenger_load;
53. double payload;
54. public:
55. truck(void)
56. {
57. passenger_load = 3;
58. payload = 22222.0;
59. }
60. // the following code should be in one line....
61. truck(int people, double load, int input_wheels, double
62. input_weight):vehicle(input_wheels,
63. input_weight),passenger_load(people),
64. payload(load)
65. {
66.
67. cout<<"It is me!, Constructor #5, derived class, car"<<'\n';
68. }
69. void init_truck(int how_many = 4, double max_load = 24000.0);
70. double efficiency(void);
71. int passengers(void) {return passenger_load;}
72. };
73.
74. // main program
75. int main()
76. {
77. vehicle unicycle(1, 12.5);
78.
79. // unicycle.initialize(1, 12.5);
80. cout<<"The unicycle has "<<unicycle.get_wheels()<<" wheel.\n";
81. cout<<"The unicycle's wheel load is "<<unicycle.wheel_load()<<
82. " kg on the single tire.\n";
83. cout<<"The unicycle weighs "<<unicycle.get_weight()<<" kg.\n\n";
84.
85. // constructor in the car class called to construct an object,
86. // after base class constructor called
87. car sedan_car(5, 4, 3500.0);
88.
89. // constructor in the car class called to construct object
90. // sedan_car.initialize(4, 3500.0, 5);
91. cout<<"The sedan car carries "<<sedan_car.passengers()<<" passengers.\n";
92. cout<<"The sedan car weighs "<<sedan_car.get_weight()<<" kg.\n";
93. cout<<"The sedan car's wheel load is "<<sedan_car.wheel_load()<<
94. " kg per tire.\n\n";
95.
96. // constructor in the base class called to construct an object
97. truck trailer(1, 33675.0, 18, 12500.0);
98.
99. // trailer.initialize(18, 12500.0);
100. // trailer.init_truck(1, 33675.0);
101. cout<<"The trailer weighs "<<trailer.get_weight()<<" kg.\n";
102. cout<<"The trailer's efficiency is "<<100.0 * trailer.efficiency()<<" %.\n";
103.
104. // system("pause");
105. return 0;
106. }
107.
108. // base and derived class implementation part
109. // initialize to any data desired
110. void vehicle::initialize(int input_wheels, double input_weight)
111. {
112. wheels = input_wheels;
113. weight = input_weight;
114. }
115.
116. void car::initialize(int input_wheels, double input_weight, int people)
117. {
118. passenger_load = people;
119. wheels = input_wheels;
120. weight = input_weight;
121. }
122.
123. void truck::init_truck(int how_many, double max_load)
124. {
125. passenger_load = how_many;
126. payload = max_load;
127. }
128.
129. double truck::efficiency(void)
130. {
131. return (payload / (payload + weight));
132. }
The additional constructor added to the vehicle class in lines 12 through 22 as shown below is nothing special; it is just like some of the constructors we have studied earlier.
...
vehicle(void)
{
wheels = 7; weight = 11111.0;
cout<<"It is me!, Constructor #1, own by base class"<<'\n';
}
vehicle(int input_wheels, double input_weight)
{
wheels = input_wheels; weight = input_weight;
cout<<"It is me!, Constructor #2, own by base class"<<'\n';
}
...
It is used in line 77 of the main program as shown below, where we define unicycle with two values passed in to be used when executing this constructor.
vehicle unicycle(1, 12.5);
The constructor for the car class which is declared in lines 34 through 44 as shown below is a little bit different, because we pass in three values. One of the values, named people, is used within the derived class itself to initialize the member variable named passenger_load.
...
car(void)
{ passenger_load = 4; cout<<"It is me!, Constructor #3, derived class, car"<<'\n'; }
car(int people, int input_wheels, double input_weight):vehicle(input_wheels, input_weight), passenger_load(people)
{ cout<<"It is me!, Constructor #4, derived class, car"<<'\n'; }
...
The other two literal values however, must be passed to the base class somehow in order to initialize the number of wheels and the weight.
This is done by using a member initializer, and is illustrated in this constructor. The colon near the end of line 40 as shown below indicates that a member initializer list follows, and all entities between the colon and the opening brace of the constructor body are member initializers.
car(int people, int input_wheels, double input_weight):vehicle(input_wheels,
input_weight), passenger_load(people)
The first member initializer as shown below and looks like a constructor call to the vehicle class that requires two input parameters.
...vehicle(input_wheels, input_weight)...
...passenger_load(people)
|
|
This may seem to be very strange, but the elements of the member initializer list are not executed in the order in which they appear in the list. The constructors for the inherited classes are executed first, in the order of their declaration in the class header.
When using multiple inheritance, (will be discussed in next Module) several classes can be listed in the header line, but in this program, only one is used.
The member variables are then initialized, but not in the order as given in the list, but in the order in which they are declared in the class. Finally, the code within the constructor block is executed, if there is any code in the block.
The destructors must be executed in reverse order from the construction order, but if there are two constructors with different construction order defined, which should define the destruction order? The correct answer is neither. The system uses the declaration order for construction order and reverses it for the destruction order.
You will notice that the truck class uses one initializer for the base class constructor and two member initializers, one to initialize the passenger_load, and another one to initialize the payload. The body of the constructor, much like the car class, is almost empty. This should be put in one line.
truck(int people, double load, int input_wheels, double
input_weight):vehicle(input_wheels,
input_weight), passenger_load(people),
payload(load)
The two constructors in the car class and the truck class are called to construct objects in lines 87 and 97 as shown below for a car and a truck object respectively as illustrations in this program example.
...
car sedan_car(5, 4, 3500.0);
...
truck trailer(1, 33675.0, 18, 12500.0);
...
Examine the program example named inherit6.cpp for examples of the use of an array of objects and a pointer to an object.
In this program, the objects are instantiated from an inherited class and the purpose of this program is to illustrate that there is nothing special about a derived class. A class acts and used as usual whether it is a base class or a derived class.
1. // program inherit6.cpp
2. #include <iostream>
3.
4. using namespace std;
5.
6. // base and derived class declaration part
7. class vehicle
8. {
9. protected:
10. int wheels;
11. double weight;
12. public:
13. vehicle(void)
14. { wheels = 7; weight = 11111.0;
15. cout<<"Constructor #1, own by base class"<<'\n';}
16. vehicle(int input_wheels, double input_weight)
17. { wheels = input_wheels; weight = input_weight;
18. cout<<"Constructor #2, own by base class"<<'\n';}
19.
20. void initialize(int input_wheels, double input_weight);
21. int get_wheels(void) {return wheels;}
22. double get_weight(void) {return weight;}
23. double wheel_load(void) {return (weight/wheels);}
24. };
25.
26. class car : public vehicle
27. {
28. int passenger_load;
29. public:
30. car(void)
31. {passenger_load = 4; cout<<"Constructor #3, derived class, car"<<"\n\n";}
32.
33. car(int people, int input_wheels, double input_weight):vehicle(input_wheels,
34. input_weight),passenger_load(people)
35. {cout<<"Constructor #4 derived class, car"<<'\n'; }
36.
37. void initialize(int input_wheels, double input_weight, int people = 4);
38. int passengers(void) {return passenger_load;}
39. };
40.
41. class truck : public vehicle
42. {
43. int passenger_load;
44. double payload;
45. public:
46. truck(void)
47. {passenger_load = 3;
48. payload = 22222.0;}
49.
50. truck(int people, double load, int input_wheels, double
51. input_weight):vehicle(input_wheels,
52. input_weight),passenger_load(people),
53. payload(load)
54. { }
55. void init_truck(int how_many = 4, double max_load = 24000.0);
56. double efficiency(void);
57. int passengers(void) {return passenger_load;}
58. };
59.
60. // the main program
61. int main()
62. {
63. vehicle unicycle;
64.
65. unicycle.initialize(1, 12.5);
66.
67. cout<<"The unicycle has " <<unicycle.get_wheels()<<" wheel.\n";
68. cout<<"The unicycle's wheel load is "<<unicycle.wheel_load()<<
69. " kg on the single tire.\n";
70. cout<<"The unicycle weighs "<<unicycle.get_weight()<<" kg.\n\n";
71.
72. car sedan_car[3];
73. // an array of object with 3 elements
74. int index;
75. // variable used for counter
76. for (index = 0 ; index < 3 ; index++)
77. // count and execute
78. {
79. sedan_car[index].initialize(4, 3500.0, 5);
80. cout<<"Count no. #" <<index<<'\n';
81. cout<<"The sedan car carries "<<sedan_car[index].passengers()<<"
82. passengers.\n";
83. cout<<"The sedan car weighs "<<sedan_car[index].get_weight()<<" kg.\n";
84. cout<<"The sedan car's wheel load is "<<sedan_car[index].wheel_load()<<
85. " kg per tire.\n\n";
86. }
87.
88. truck *trailer; // a pointer
89.
90. trailer = new truck;
91. // initialize to point to something...point to an object
92.
93. if (trailer == NULL)
94. {
95. cout<<"Memory allocation failed\n";
96. exit(EXIT_FAILURE);
97. }
98. trailer->initialize(18, 12500.0);
99. trailer->init_truck(1, 33675.0);
100. cout<<"The trailer weighs " << trailer->get_weight()<<" kg.\n";
101. cout<<"The trailer's efficiency is "<<100.0 * trailer->efficiency()<<
102. " %.\n";
103.
104. delete trailer;
105. // deallocate the object
106.
107.
108. // system("pause");
109. return 0;
110. }
111.
112. // base and derived class implementation part
113. // initialize to any data desired
114. void vehicle::initialize(int input_wheels, double input_weight)
115. {
116. wheels = input_wheels;
117. weight = input_weight;
118. }
119.
120. void car::initialize(int input_wheels, double input_weight, int people)
121. {
122. passenger_load = people;
123. wheels = input_wheels;
124. weight = input_weight;
125. }
126.
127. void truck::init_truck(int how_many, double max_load)
128. {
129. passenger_load = how_many;
130. payload = max_load;
131. }
132.
133. double truck::efficiency(void)
134. {
135. return (payload / (payload + weight));
136. }
This program is identical to the previous program until we get to the main() program where we find an array of 3 objects of class car declared in line 72 as shown below:
car sedan_car[3];
It should be obvious that any operation that is legal for a simple object is also legal for an object that is part of an array, but we must tell the system which object of the array we are interested in by adding the array subscript as we do in lines 79, 81, 83 and 84 as shown below:
sedan_car[index].initialize(4, 3500.0, 5);
cout<<"Count no. #" <<index<<'\n';
cout<<"The sedan car carries "<<sedan_car[index].passengers()<<" passengers.\n";
cout<<"The sedan car weighs "<<sedan_car[index].get_weight()<<" kg.\n";
cout<<"The sedan car's wheel load is "<<sedan_car[index].wheel_load()<<" kg per tire.\n\n";
You will notice, in line 88, we do not declare an object of type truck but a pointer to an object of type truck. In order to use the pointer, we must give it something to point at which we do in line 90 by dynamically allocating an object size by using new keyword as shown below:
truck *trailer; // a pointer
trailer = new truck;
// initialize to point to something...point to an object
Once the pointer has an object to point to, we can use the object in the same way we would use any object, but we must use the pointer notation to access any of the methods of the object. This is illustrated for you in lines 98 through 101 as shown below:
trailer->initialize(18, 12500.0);
trailer->init_truck(1, 33675.0);
cout<<"The trailer weighs " << trailer->get_weight()<<" kg.\n";
cout<<"The trailer's efficiency is "<<100.0 * trailer->efficiency()<<" %.\n";
Finally, we de-allocate the object in line 104 as shown below.
delete trailer;
// de-allocate the object from memory
Compile and run this program.
tenouk C++ object inheritance tutorial