The source code for this session is available in C++ Multi Inheritance source code.
Able to understand and use:
Multiple inheritances are the ability to inherit member variables and methods from more than one base class into a derived class.
This feature will enhance the functionalities of the new class and its reusability but we have to deal with few issues regarding the multi inheritance later.
The biggest problem with multiple inheritances involves the inheritance of variables or methods with duplicated names from two or more base classes. The question is: which variables or methods should be chosen as the inherited entities? This will be illustrated in the following program examples.
Actually, no new trick to solve this problem. It is same solution as used in the previous program examples by using the scope operator (::) for duplicated functions name.
| 16.2 First Multiple Inheritance
1. // program mulinher1.cpp 2. #include <iostream> 3. using namespace std; 4. 5. // class declaration and implementation part 6. // base class #1 7. class moving_van 8. { 9. protected: 10. float payload; 11. float gross_weight; 12. float mpg; 13. // this variable only available for derived class 14. // because of the protected keyword 15. public: 16. void initialize(float pl, float gw, float input_mpg) 17. { 18. payload = pl; 19. gross_weight = gw; 20. mpg = input_mpg; 21. }; 22. 23. float efficiency(void) 24. { 25. return (payload / (payload + gross_weight)); 26. }; 27. 28. float cost_per_ton(float fuel_cost) 29. { 30. return (fuel_cost / (payload / 2000.0)); 31. }; 32. }; 33. 34. // base class #2 35. class driver 36. { 37. protected: 38. float hourly_pay; 39. public: 40. void initialize(float pay) {hourly_pay = pay; }; 41. float cost_per_mile(void) {return (hourly_pay / 55.0); } ; 42. }; 43. 44. // derived class 45. // inherit from two different base classes 46. class driven_truck : public moving_van, public driver 47. { 48. public: 49. void initialize_all(float pl, float gw, float input_mpg, float pay) 50. { payload = pl; 51. gross_weight = gw; 52. mpg = input_mpg; 53. hourly_pay = pay; 54. }; 55. 56. float cost_per_full_day(float cost_of_gas) 57. { 58. return ((8.0 * hourly_pay) + (8.0 * cost_of_gas * 55.0) / mpg); 59. }; 60. }; 61. 62. // the main program 63. int main() 64. { 65. // instantiate objects… 66. driven_truck john_merc; 67. john_merc.initialize_all(20000.0, 12000.0, 5.2, 12.50); 68. 69. cout<<"The efficiency of the Merc truck is "<<john_merc.efficiency()<< 70. " %\n"; 71. cout<<"The cost per mile for John to drive Merc is 72. $"<<john_merc.cost_per_mile()<<"\n"; 73. cout<<"The cost per day for John to drive Merc is 74. $"<<john_merc.cost_per_full_day(1.129)<<"\n"; 75. 76. // system("pause"); 77. 78. return 0; 79. }
|
In order to keep the program as simple as possible for our study, all of the methods are defined as inline functions.
All variables in both classes are declared to be protected so they will be readily available for use in any class that inherits them only.
Beginning in line 46, we define another class named driven_truck which inherits all of the variables and methods from both of the previously defined classes, moving_van anddriver.
In the last two Modules, we have discussed how to inherit a single class into another class, and to inherit two or more classes, the same technique is used except that we use a list of inherited classes separated by commas as illustrated in line 46, the class header.
class driven_truck : public moving_van, public driver
We use the keywordpublic prior to the name of each inherited class in order to be able to freely use the methods within the derived class. In this case, we didn't define any new variables, but we did introduce two new methods into the derived class in lines 49 through 59 as shown below.
void initialize_all(float pl, float gw, float input_mpg, float pay)
{
payload = pl;
gross_weight = gw;
mpg = input_mpg;
hourly_pay = pay;
};
float cost_per_full_day(float cost_of_gas)
{ return ((8.0 * hourly_pay) + (8.0 * cost_of_gas * 55.0) / mpg); };
We define an object named john_merc which is composed of four variables, three from the moving_van class, and one from the driver class. Any of these four variables can be manipulated in any of the methods defined within thedriven_truck class in the same way as in a singly inherited situation. A few examples are given in lines 67 through 74 of the main program as shown below.
john_merc.initialize_all(20000.0, 12000.0, 5.2, 12.50);
cout<<"The efficiency of the Merc truck is "<<john_merc.efficiency()<<" %\n";
cout<<"The cost per mile for John to drive Merc is $"<<john_merc.cost_per_mile()<<"\n";
cout<<"The cost per day for John to drive Merc is $"<<john_merc.cost_per_full_day(1.129)<<"\n";
16.3 Duplicate Method Names
|
1. // program mulinher2.cpp
2. #include <iostream>
3. using namespace std;
4.
5. // declaration and implementation class part
6. // base class #1
7. class moving_van
8. {
9. protected:
10. float payload;
11. float gross_weight;
12. float mpg;
13. public:
14. void initialize(float pl, float gw, float input_mpg)
15. {
16. payload = pl;
17. gross_weight = gw;
18. mpg = input_mpg;
19. };
20.
21. float efficiency(void)
22. {
23. return (payload / (payload + gross_weight));
24. };
25.
26. float cost_per_ton(float fuel_cost)
27. {
28. return (fuel_cost / (payload / 2000.0));
29. };
30.
31. float cost_per_full_day(float cost_of_gas) //number one
32. {
33. return (8.0 * cost_of_gas * 55.0 / mpg);
34. };
35. };
36.
37. // base class #2
38. class driver
39. {
40. protected:
41. float hourly_pay;
42. public:
43. // same method name as in moving van class…
44. void initialize(float pay) {hourly_pay = pay; };
45. float cost_per_mile(void) {return (hourly_pay / 55.0); } ;
46. float cost_per_full_day(float overtime_premium) //number two
47. {return (8.0 * hourly_pay); };
48. };
49.
50. // derived class
51. // notice also the duplicated method names used
52. class driven_truck : public moving_van, public driver
53. {
54. public:
55. void initialize_all(float pl, float gw, float input_mpg, float pay)
56. {
57. payload = pl;
58. gross_weight = gw;
59. mpg = input_mpg;
60. hourly_pay = pay;
61. };
62.
63. float cost_per_full_day(float cost_of_gas) // #3
64. {
65. return ((8.0 * hourly_pay) + (8.0 * cost_of_gas * 55.0) / mpg);
66. };
67. };
68.
69. // the main program
70. int main()
71. {
72. driven_truck john_merc;
73.
74. john_merc.initialize_all(20000.0, 12000.0, 5.2, 12.50);
75. cout<<"The efficiency of the Merc is "<<john_merc.efficiency()<<" %\n";
76. cout<<"The cost per mile for John to drive is
77. $"<<john_merc.cost_per_mile()<<"\n\n";
78.
79. cout<<" calling the appropriate method using:\n";
80. cout<<" john_merc.moving_van::cost_per_full_day()\n";
81. cout<<"--------------------------------------------\n";
82. cout<<"The cost per day for the Merc is
83. $"<<john_merc.moving_van::cost_per_full_day(1.129)<<"\n\n";
84.
85. cout<<" calling the appropriate method using:\n";
86. cout<<" john_merc.driver::cost_per_full_day()\n";
87. cout<<"----------------------------------------\n";
88. cout<<"The cost of John for a full day is
89. $"<<john_merc.driver::cost_per_full_day(15.75)<<"\n\n";
90.
91. cout<<" calling the appropriate method using:\n";
92. cout<<" john_merc.driven_truck::cost_per_full_day()\n";
93. cout<<"----------------------------------------------\n";
94. cout<<"The cost per day for John to drive Merc is
95. $"<<john_merc.driven_truck::cost_per_full_day(1.129)<<"\n";
96.
97. // system("pause");
98. return 0;
99. }
A new method has been added to all three of the classes named cost_per_full_day(). This was done intentionally to illustrate how the same method name can be used in all three classes. The class definitions are no problem at all; the methods are simply named and defined as shown.
The problem comes when we wish to use one of the methods since they are all have same name, numbers and types of parameters and identical return types. This prevents some sort of an overloading rule to disambiguate the message sent to one or more of the methods.
The method used to disambiguate the method calls are illustrated in lines 82-83, 88-89, and 94-95 of the main() program as shown below:
cout<<"The cost per day for the Merc is $"<<john_merc.moving_van::cost_per_full_day(1.129)<<"\n\n";
...
cout<<"The cost of John for a full day is $"<<john_merc.driver::cost_per_full_day(15.75)<<"\n\n";
...
cout<<"The cost per day for John to drive Merc is $"<<john_merc.driven_truck::cost_per_full_day(1.129)<<"\n";
...
The solution is simple by pre-pending the class name to the method name with the double colon (::,scope operator) as used in the method implementation definition. This is referred to as qualifying the method name. Actually, qualification is not necessary in line 95 since it is the method in the derived class and it will take precedence over the other method names.
Actually, you could qualify all method calls, but if the names are unique, the compiler can do it for you and make your code easier to be written and read. Be sure to compile and run this program and study the output and the source code.
tenouk fundamental of C++ multi inheritance tutorial