430 likes | 449 Views
Inheritance: Part I. Structuring ‘classes’. class Employee { string firstName; string familyName; … } class Manager { Employee e; list<Employee*> group; … }. class X { … } class Y { X x; … }. Y has a X as a component, but a y of Y is NOT a x of X.
E N D
Structuring ‘classes’ class Employee { string firstName; string familyName; … } class Manager { Employee e; list<Employee*> group; … } class X { … } class Y { X x; … } Y has a X as a component, but a y of Y is NOT a x of X a ‘Manager’ is an ‘Employee’
Relationships Between Classes • Composition (class in class) • “has-a” relationship • Object contains one or more objects of other classes as members • Example: A car has a wheel • Inheritance (derived class) • “is-a” relationship • Derived class object can be treated as base class object • Example: A car is a vehicle COMP152 3
Example COMP152 4
Another Example COMP152 5
Derived Class class Employee { string firstName; string familyName; … } class Manager : public Employee { list<Employee*> group; … } a ‘Manager’ is a ‘Employee’! a derived class object can be treated as a base class object.
(Public) Inheritance Base class (super-class), derived class (sub-class) • Derived class object is a specialization and is a ‘superset’ of the data of its base class object Derived class inherits all members of base class (and members of all its ancestor classes) • Public members of the base class • Inherited, so accessible • Private members of the base class • Not accessible directly: comes as a surprise, but ‘privacy’ would have been rendered meaningless if allowed by deriving a new class • Accessed through public member functions Friend functions are not inherited COMP152 7
class Employee { public: string fullName(); private: string firstName; string familyName; … } class Manager : public Employee { public: void print() const; private: list<Employee*> group; … } void Manager::print() const { cout << fullName() << endl; } Void Manager::print() const { cout << firstName << familyName << endl; } Yes. No, because of privacy!
Class-in-Class vs. Inheritance A class declares another class as its data member, hence creating an object within another object Inheritance and class-in-class are two quite different things and concepts in implementation and OOP. Inheritance has a "is-a" relationship between derived class and base class, while class-in-class is a "has-a" relationship Generally, we can decide whether to use inheritance or class-in-class by common sense. If we can find some common relationship between two or more things, we should use inheritance. • For example, Citizen and Student with Citizen as the base class. It makes no sense to implement a Citizen class inside a Student class. In class-in-class, the inner class is a standalone object. Thus, the inner class and the outer class do not share the powerful features in inheritance (such as polymorphism and dynamic binding). COMP152 9
‘protected’ members The ‘protected’ is the ‘shared privacy’ between base and derived classes ! the private data members in the base class cannot be accessed by its derived classes the protected data members in the base class can be accessed by its derived classes, but not other non-derived classes COMP152 10
class Employee { protected: string firstName; string familyName; … } class Manager : public Employee { public: void print() const; private: list<Employee*> group; … } void Manager::print() const { cout << firstName << familyName << endl; }
Protection control: public, protected, private Intermediate level of protection between public and private • For both data members and function members • Want the derived class to directly access members while forbid other classes to access them directly protected members in the Base class are accessible to • Base class members • Base class friends • Derived class members • Derived class friends COMP152 12
Pros/Cons of ‘Protected’ Advantages • Derived class can modify values directly • Avoid set/get method call overhead Slight increase in performance Disadvantages • No validity checking: Derived class can assign illegal value to protected members • Implementation-dependent on the base class • Derived class functions are usually very likely dependent on base class implementation • Using protected access, base class implementation changes may result in derived class modifications, e.g., a change to a different printing format in the base class may cause the printing function to be changed in the derived class • This leads to fragile (brittle) software COMP152 13
Constructors of Derived Classes class Y : public X { public Y::Y(); }; Y::Y() : X() { … }; COMP152 14
class Employee { protected: Employee(); string firstName; string familyName; … } class Manager : public Employee { private: list<Employee*> group; int level; } Employee e; Manager m; // use default ‘employee’ constructor If no constructor, use the default base constructor. COMP152 15
class Employee { public: Employee(); private: string firstName; string familyName; … } class Manager : public Employee { public: Manager(); private: list<Employee*> group; int level; } Manager::Manager() : Employee() { level = … group = … } Employee e; Manager m; // use ‘manager’s constructor COMP152 16
Passing ‘Arguments’ between ‘Base’ and ‘Derived’ Class Constructors class Employee { private: string firstName; string familyName; … } class Manager : public Employee { private: list<Employee*> group; int level; } Employee::Employee(const string& first, const string& family) { } Manager::Manager(const string& first, const string& family, int l) : Employee(n), level(l) { … } If a base class has a constructor with arguments, then it is compulsary for the derived class to have a constructor and pass the arguments to the base class constructor. COMP152 17
Constructors of Derived Classes and Order of Construction • Class objects are constructed from the bottom up: • First the base, • Then the members, • And then the derivated class itself. • Members and bases are constructed in order of declaration. • When a program creates a derived-class object: • The derived-class constructor immediately calls the base-class constructor • The base-class constructor’s body (i.e., within {}) executes • Then the derived class’s member initializer list execute • Finally the derived-class constructor’s body executes • This process cascades up the hierarchy if the hierarchy contains more than two levels in a recursive manner COMP152 18
Destructor class Y : public X { public Y::~Y(); }; Y::~Y() { … }; COMP152 19
Order of Destruction Class objects are destroyed in the opposite order of the construction: • First the derived class itself, • Then the members, • And then the base. Members and bases are destroyed in the reverse order of declaration. Example on order of construction and destruction • CommissionEmployee4.h, CommissionEmployee4.cpp, BasePlusCommissionEmployee4.h, BasePlusCommissionEmployee4.cpp, order.cpp COMP152 20
Over-riding (not over-loading): Reusing Operations of Base Classes class X { f(); }; Class Y : public X {}; void Y::f() { … X::f(); … } Derived class may extend or replace base class function of the same name • Therefore, it hides (or overrides) the base-class version of the function • Still possible to call the base class function with scope resolution operator COMP152 21
class X { public: void print(){cout << "base\n";} }; class Y : public X { public: void print( int i ){ cout << i << " Derived\n";} void print( char ch ){ cout << ch << " Derived\n";} }; int main(){ Y y; y.print( 2 ); // print 2 Derived y.print(‘y'); // print y Derived // y.print(); Not O.K.: no matching function for Y::print() } COMP152 22
Remarks Beware of ‘infinite recursion’ in function over-riding, if the scope :: operator is not prefixed with the name of the base class when referencing the base class’s member function causes infinite recursion which version of the function to call or function resolution is a major issue! static or dynamic binding! COMP152 23
Example CommissionEmployee • First name, last name, SSN (Social Security Number, i.e., ID), commission rate, gross sale amount BasePlusCommissionEmployee • CommissionEmployee: First name, last name, SSN, commission rate, gross sale amount • And also base salary Class BasePlusCommissionEmployee • Much of the code is similar to CommissionEmployee • Additions • private data member baseSalary • Methods setBaseSalary and getBaseSalary COMP152 24
Derived from class CommissionEmployee • Is a CommissionEmployee • Inherits all public members • Use base-class initializer syntax to initialize base-class data member Has data member baseSalary Base class implementation • CommissionEmployee1.h, CommissionEmployee1.cpp Derived class implementation • BasePlueCommissionEmployee1.h, BasePlusCommissionEmployee1.cpp Compilation error because derived class cannot directly access private members of CommissionEmployee class in print() and earnings() COMP152 25
tester2.cpp Sample Output Employee information obtained by get functions: First name is Bob Last name is Lewis Social security number is 333-33-3333 Gross sales is 5000.00 Commission rate is 0.04 Base salary is 300.00 Updated employee information output by print function: base-salaried commission employee: Bob Lewis social security number: 333-33-3333 gross sales: 5000.00 commission rate: 0.04 base salary: 1000.00 Employee's earnings: $1200.00 COMP152 26
Summary ‘is-a’ relationship • Different from ‘has-a’ or ‘uses-a’, or … by class-in-class Public inheritance • Public • Private ‘protected’ Constructors/destructors Redefinition (over-riding) which version for which object??? Not inherited: • Friend functions COMP152 27
order.cpp Sample Output (1/2) 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 CommissionEmployee constructor called for object in block; destructor called immediately as execution leaves scope Base-class CommissionEmployee constructor executes first when instantiating derived-class BasePlusCommissionEmployee object 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 Derived-class BasePlusCommissionEmployee constructor body executes after base-class CommissionEmployee’s constructor finishes execution Base-class CommissionEmployee constructor executes first when instantiating derived-class BasePlusCommissionEmployee object COMP152 28
order.cpp Sample Output (2/2) 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 Derived-class BasePlusCommissionEmployee constructor body executes after base-class CommissionEmployee’s constructor finishes execution Destructors for BasePlusCommissionEmployee object called in reverse order of constructors 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 Destructors for BasePlusCommissionEmployee object called in reverse order of constructors COMP152 29
A More General Derived Class class Y : public X {…} class Y : protected X {…}; class Y : private X {…}; COMP152 31
Increasing Access Restrictions public Derived class Base class public protected public protected protected public protected protected protected private public protected private private public inheritance (written as class derived: public base) • Base class public members derived class public members • Base class protected members derived class protected members • All classes can directly access the public members • Only the derived classes can directly access the protected members protected inheritance (written as class derived: protected base) • Base class public and protected members derived class protected members • Classes in the inheritance hierarchy can still access the members (because they are protected members), but not for other classes private inheritance (written as class derived: private base) • Base class public and protected members derived class private members • Classes in the downstream inheritance hierarchy can no longer access the members (and neither can all the other classes) COMP152 32
Types of Inheritance and Member Access COMP152 33
class Base { public: void f() {cout << "Base::f()" << endl;} protected: void g() {cout << "Base::g()" << endl;} }; class public_derived: public Base { }; class protected_derived: protected Base { }; class private_derived: private Base { }; int main(){ Base b; public_derived pub_d; protected_derived prot_d; private_derived priv_d; b.f(); // b.g(); error: 'void Base::g()' is protected pub_d.f(); // pub_d.g(); error: 'void Base::g()' is protected // prot_d.f(); error: 'void Base::f()' is inaccessible // prot_d.g(); error: 'Base' is not an accessible base of 'protected_derived' // priv_d.f(); similar error as above // priv_d.g(); similar error as above return 1; } COMP152 34
Class hierarchy Direct base class • Inherited explicitly (one level up hierarchy) • E.g., driver licenses and license Indirect base class • Inherited two or more levels up hierarchy • E.g., car license and license Single inheritance • Inherits from one base class • E.g., the above license example Multiple inheritance • Inherits from multiple base classes • Base classes possibly unrelated • E.g., A “university student” is both a “hard-working person” and a “clever person” COMP152 35
Multiple Inheritance When a derived class inherits members from two or more base classes • Provide comma-separated list of base classes after the colon following the derived class name Can cause ambiguity problems • Should be used only by experienced programmers • Newer languages do not allow multiple inheritance • A common issue occurs if more than one base class contains a member with the same name • Solved by using the scope resolution operator (by the user!) COMP152 36
Multiple Inheritence (Cont.) Should be used when an “is a” relationship exists between a new type and two or more existing types • i.e. type A “is a” type B and type A “is a” type C Can introduce complexity into a system • Great care is required in the design of a system to use multiple inheritance properly • Should not be used when single inheritance and/or composition will do the job COMP152 37
Example:Base1.h, Base2.h, Derived.h, Derived.cpp, multiple.cpp COMP152 38
Base1.h class Base1 { public: Base1( int parameterValue ) { value = parameterValue; } int getData() const { return value; } protected: int value; }; Class Base1 declares member function getData COMP152 39
Base2.h class Base2 { public: Base2( char characterData ) { letter = characterData; } char getData() const { return letter; } protected: char letter; }; Class Base2 also declares member function getData, same name as Base1 COMP152 40
Derived.h #include "Base1.h" #include "Base2.h" class Derived : public Base1, public Base2 { friend ostream& operator<<( ostream&, const Derived&); public: Derived(int, char, double); double getReal() const; private: double real; }; Class Derived inherits from both class Base1 and class Base2 through multiple inheritance COMP152 41
multiple.cpp Sample Output Object base1 contains integer 10 Object base2 contains character Z Object derived contains: Integer: 7 Character: A Real number: 3.5 Data members of Derived can be accessed individually: Integer: 7 Character: A Real number: 3.5 Derived can be treated as an object of either base class: base1Ptr->getData() yields 7 base2Ptr->getData() yields A Note the use of base-class pointer pointing to a derived-class objects • Invoking the member function of the derived object COMP152 42
Software Engineering: Customizing Existing Software with Inheritance • Inheriting from existing classes • Can include additional members • Can redefine base-class members • No direct access to base class’s source code • Only links to object code • Good for those independent software vendors (ISVs) • Develop proprietary code for sale/license • Available in object-code format • Users derive new classes • Without accessing ISV proprietary source code COMP152 43