Inheritance - Polymorphism: Protected
Inheritance - Polymorphism: Protected
Inheritance - Polymorphism: Protected
12.2 Inheritance: Base and Derived Classes 12.2 Inheritance: Base and Derived Classes
• Base and derived classes • Implementation of public inheritance
– Often an object from a derived class (subclass) is also an class CommissionWorker : public Employee {
object of a base class (superclass) ...
• A rectangle is a derived class in reference to a quadrilateral and };
a base class in reference to a square – Class CommissionWorker inherits from class
Employee
• Inheritance examples
Base class Derived classes – friend functions not inherited
Student GraduateStudent – private members of base class not accessible from
UndergraduateStudent
derived class
Shape Circle
Triangle
Rectangle
Loan CarLoan
HomeImprovementLoan
MortgageLoan
Employee FacultyMember
StaffMember
Account CheckingAccount
SavingsAccount
1
4/5/2023
2
4/5/2023
33 assert( firstName != 0 ); // terminate if not allocated 64 double wage; // wage per hour
34 strcpy( firstName, first ); 65 double hours; // hours worked for week
35 66 };
36 lastName = new char[ strlen( last ) + 1 ]; 67
37
38
assert( lastName != 0 ); // terminate if not allocated
strcpy( lastName, last ); • 1.1 Function 69 // test. 12.5: hourly.cpp
39 } 70 // Member function definitions for class HourlyWorker
40 definitions 71 #include <iostream>
41 // Output employee name 72
42 void Employee::print() const 73 using std::cout;
43 { cout << firstName << ' ' << lastName; } 74 using std::endl;
44
45 // Destructor deallocates dynamically allocated memory • ---------------- 75
76 #include <iomanip>
46 Employee::~Employee()
47 { ----- 77
78 using std::ios;
48 delete [] firstName; // reclaim dynamic memory 79 using std::setiosflags;
49 delete [] lastName; // reclaim dynamic memory 80 using std::setprecision;
50 } 81
51 // test. 12.5: hourly.h
52 // Definition of class HourlyWorker
• 1.
HourlyWorker inherits
82
83
#include "hourly.h"
HourlyWo
from Employee. 84 // Constructor for class HourlyWorker
85 HourlyWorker::HourlyWorker( const char *first,
rker class 86 const char *last,
56 #include "employ.h" 87 double initHours, double initWage )
57 definition
HourlyWorker will override
88 : Employee( first, last ) // call base-class constructor
89 {
58 class HourlyWorker : public Employee { the print function. 90 hours = initHours; // should validate
59 public:
91 wage = initWage; // should validate
60 HourlyWorker( const char*, const char*, double, double );
92 }
61 double getPay() const; // calculate and return salary 93
62 void print() const; // overridden base-class print 94 // Get the HourlyWorker's pay
63 private: 95 double HourlyWorker::getPay() const { return wage * hours; }
3
4/5/2023
96
97 // Print the HourlyWorker's name and pay
98 void HourlyWorker::print() const 12.7 public, private, and protected Inheritance
99 {
100 cout << "HourlyWorker::print() is executing\n\n";
Base class Type of inheritance
101 Employee::print(); // call base-class print function member
102 access public protected private
specifier inheritance inheritance inheritance
103 cout << " is an hourly worker with pay of $"
104 << setiosflags( ios::fixed | ios::showpoint ) public in derived class. protected in derived class. private in derived class.
105 << setprecision( 2 ) << getPay() << endl;
Can be accessed directly by any Can be accessed directly by all Can be accessed directly by all
The print function is Public non-static member functions, non-static member functions non-static member functions
106 }
107 // test. 12.5: test09_05.cpp overriden in friend functions and non- and friend functions. and friend functions.
member functions.
108 // Overriding a base-class member function in a HourlyWorker.
protected in derived class. protected in derived class. private in derived class.
109 // derived class.
However, the new
Can be accessed directly by all Can be accessed directly by all Can be accessed directly by all
function still can call the
110 #include "hourly.h" Protected non-static member functions non-static member functions non-static member functions
original print function and friend functions. and friend functions. and friend functions.
111
using ::
112 int main() Hidden in derived class. Hidden in derived class. Hidden in derived class.
112 {
Can be accessed by non-static Can be accessed by non-static Can be accessed by non-static
member functions and friend member functions and friend member functions and friend
114 HourlyWorker h( "Bob", "Smith", 40.0, 10.00 ); Private
functions through public or functions through public or functions through public or
115 h.print(); protected member functions protected member functions protected member functions
116 return 0; of the base class. of the base class. of the base class.
117 }
HourlyWorker::print() is executing
4
4/5/2023
56 80 << radius << " [" << x << ", " << y << ']' << endl;
81 }
12.10 Implicit Derived-Class Object to Base- 12.10 Implicit Derived-Class Object to Base-
Class Object Conversion Class Object Conversion
• Assignment of derived and base classes • Mixing base and derived class pointers and objects
– Derived-class type and base-class type are different – Referring to a base-class object with a base-class pointer
– Derived-class object can be treated as a base-class object • Allowed
• Derived class has members corresponding to all of the base – Referring to a derived-class object with a derived-class pointer
class’s members • Allowed
• Derived-class has more members than the base-class object – Referring to a derived-class object with a base-class pointer
• Base-class can be assigned a derived-class • Possible syntax error
– Base-class object cannot be treated as a derived-class object • Code can only refer to base-class members, or syntax error
• Would leave additional derived class members undefined – Referring to a base-class object with a derived-class pointer
• Derived-class cannot be assigned a base-class • Syntax error
• Assignment operator can be overloaded to allow such an • The derived-class pointer must first be cast to a base-class pointer
assignment
5
4/5/2023
6 class Base1 {
7 public: 35 #include <iostream>
8 Base1( int x ) { value = x; } 36
9 int getData() const { return value; } 37 using std::ostream;
10 protected: // accessible to derived classes
Derived inherits from
38
Base1 and Base2.
11 int value; // inherited by derived class 39 #include "base1.h"
12 }; 40 #include "base2.h"
12 41
42 // multiple inheritance
15 // test. 12.11: base2.h 43 class Derived : public Base1, public Base2 {
16 // Definition of class Base2 44 friend ostream &operator<<( ostream &, const Derived & );
45
46 public:
6
4/5/2023
119
12.15 The diamond problem
120 return 0;
121 }
• The Diamond Problem occurs when a child class
inherits from two parent classes who both share a
Object b1 contains integer 10 common grandparent class. This is illustrated in
Object b2 contains character Z
Object d contains:
Integer: 7
the diagram below:
Character: A
Real number: 3.5
12.15 The diamond problem (continued..) 12.15 The diamond problem demo
• Here, we have a class Child inheriting from
classes Father and Mother. These two classes, in
turn, inherit the class Person because both Father
and Mother are Person.
• As shown in the testure, class Child inherits the
traits of class Person twice—once from Father and
again from Mother. This gives rise to ambiguity
since the compiler fails to understand which way
to go.
• This scenario gives rise to a diamond-shaped
inheritance graph and is famously called “The
Diamond Problem.”
7
4/5/2023
12.15 The diamond problem (continued..) 12.16 How to Fix The diamond problem?
• Now you can see the ambiguity here. The Person • The solution to the diamond problem is to use
class constructor is called twice: once when the the virtual keyword. We make the two parent
Father class object is created and next when the classes (who inherit from the same grandparent
Mother class object is created. The properties of class) into virtual classes in order to avoid two
the Person class are inherited twice, giving rise to copies of the grandparent class in the child class.
ambiguity.
• Since the Person class constructor is called twice,
the destructor will also be called twice when the
Child class object is destructed.
• Now if you have understood the problem
correctly, let’s discuss the solution to the Diamond
Problem.
12.17 The diamond problem Solution 12.17 The diamond problem Solution
• Here we have used the virtual keyword when classes
Father and Mother inherit the Person class. This is
usually called “virtual inheritance," which guarantees
that only a single instance of the inherited class (in this
case, the Person class) is passed on.
• In other words, the Child class will have a single
instance of the Person class, shared by both the Father
and Mother classes. By having a single instance of the
Person class, the ambiguity is resolved.
• The output of the above code is given below:
8
4/5/2023
9
4/5/2023
63 83 public:
64 // Return a pointer to the last name
84 Boss( const char *, const char *, double = 0.0 );
65 // Const return type prevents caller from modifying private
85 void setWeeklySalary( double );
66 // data. Caller should copy returned string before destructor
67 // deletes dynamic storage to prevent undefined pointer. 86 virtual double earnings() const;
71 } 89 double weeklySalary;
72 90 };
73 // Print the name of the Employee
91
74 void Employee::print() const
118 }
133 // Member function definitions for class CommissionWorker 164 // Set CommissionWorker's commission
134 #include <iostream> 165 void CommissionWorker::setCommission( double c )
135
166 { commission = c > 0 ? c : 0; }
136 using std::cout;
167
137
168 // Set CommissionWorker's quantity sold
138 #include "commis1.h"
169 void CommissionWorker::setQuantity( int q )
139
170 { quantity = q > 0 ? q : 0; }
150 // Constructor for class CommissionWorker
Notice the overriden
151 CommissionWorker::CommissionWorker( const char *first, 171 earnings and
152 const char *last, double s, double c, int q ) 172 // Determine CommissionWorker's earnings print functions.
153 : Employee( first, last ) // call base-class constructor 173 double CommissionWorker::earnings() const They were declared
154 {
virtual in the base
174 { return salary + commission * quantity; }
class.
155 setSalary( s );
175
156 setCommission( c );
176 // Print the CommissionWorker's name
157 setQuantity( q );
177 void CommissionWorker::print() const
158 }
178 {
159
179 cout << "\nCommission worker: ";
160 // Set CommissionWorker's weekly base salary
10
4/5/2023
238 // Definition of class HourlyWorker 258 // Member function definitions for class HourlyWorker
260
262
11
4/5/2023
326 Boss b( "John", "Smith", 800.00 ); Boss: John Smith earned $800.00 360
327 b.print(); // static binding
Boss: John Smith earned $800.00 361 // Make virtual function calls off a base-class reference
328 cout << " earned $" << b.earnings(); // static binding
329 virtualViaPointer( &b ); // uses dynamic
Boss: binding
John Smith earned $800.00 362 // using dynamic binding.
330 virtualViaReference( b ); // uses dynamic binding
331 363 void virtualViaReference( const Employee &baseClassRef )
332 Call function
CommissionWorker c( "Sue", "Jones", 200.0, 3.0, 150 ); print using the object itself.
364 { Take in base class reference, call
333 c.print(); // static binding
Commission worker: Sue Jones earned $650.00 the virtual function print.
334 cout << " earned $" << c.earnings(); // static binding 365 baseClassRef.print();
335 virtualViaPointer( &c ); // usesCommission worker: Sue Jones earned $650.00
dynamic binding
336 virtualViaReference( c ); // usesCommission
dynamic binding 366 cout << " earned $" << baseClassRef.earnings();
worker: Sue Jones earned $650.00
337 367 }
338 PieceWorker p( "Bob", "Lewis", 2.5, 200 );Call function print, using a base-class pointer.
339 p.print(); // static binding
340 cout << " earned $" << p.earnings(); This
// uses virtual
static binding functions and dynamic binding. Boss: John Smith earned $800.00
341 virtualViaPointer( &p ); // uses dynamic binding Boss: John Smith earned $800.00
Piece worker: Bob Lewis earned $500.00
342 virtualViaReference( p ); // uses dynamic binding Boss: John Smith earned $800.00
343 Piece worker: Bob Lewis earned $500.00 Commission worker: Sue Jones earned $650.00
344 HourlyWorker h( "Karen", "Price", 12.75, 40 ); Piece worker: Bob Lewis earned $500.00 Commission worker: Sue Jones earned $650.00
345 h.print(); // static binding Commission worker: Sue Jones earned $650.00
346 cout << " earned $" << h.earnings();
Call function print, using a base-
// static binding Piece worker: Bob Lewis earned $500.00
347 virtualViaPointer( &h ); // uses class reference.
dynamic binding Piece worker: Bob Lewis earned $500.00
Piece worker: Bob Lewis earned $500.00
348 virtualViaReference( h ); // uses dynamic binding
349 cout << endl; This uses virtual functions and Hourly worker: Karen Price earned $550.00
Hourly worker: Karen Price earned $550.00
350 return 0; dynamic binding. Hourly worker: Karen Price earned $550.00
351 } Hourly worker: Karen Price earned $550.00
352 Hourly worker: Karen Price earned $550.00
353 // Make virtual function calls off a base-class pointer
354 // using dynamic binding. Hourly worker: Karen Price earned $550.00
355 void virtualViaPointer( const Employee *baseClassPtr )
356 {
357 baseClassPtr->print();
Take in a baseclass pointer, call
358 cout << " earned $" << baseClassPtr->earnings();
359 }
the virtual function print.
12