1 / 66

Inheritance

Inheritance. Inheritance is a relationship among classes wherein one class shares the structure and/or behavior that is defined in one or more other classes (is-a) Base class – superclass (parent) Derived class (subclass, child). The benefit of inheritance.

ronat
Download Presentation

Inheritance

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Inheritance • Inheritance is a relationship among classes wherein one class shares the structure and/or behavior that is defined in one or more other classes (is-a) • Base class – superclass (parent) • Derived class (subclass, child)

  2. The benefit of inheritance • The goal of any software is that you could go back and make changes to the ancestor and be sure those changes will be reflected in all the descendents as well • Example: If you went to a tailor and asked him to make a shirt just like the one he made for you earlier except this time you need a button-down collar, then you would be practicing inheritance

  3. Inheritance • Both Student and Teacher is a person Person Teacher Student

  4. Constructors/Destructors • By default, constructors and destructors inherited from the superclass, will apply to data members inherited from the superclass • Write your own constructors/destructors for the subclass when • You add new data members to the subclass and need to initialize/destroy them • You want to change how other data members are initialized/destroyed

  5. Constructors/Destructors • Some derived classes need constructors. If a base class has constructors, then a constructor must be invoked. Default constructors can be invoked implicitly. • However, if all constructors for a base require arguments, then a constructor for that base must be explicitly called. • Arguments for the base class’s constructor are specified in the definition of a derived class’ constructor

  6. examples class Counter { protected: unsigned int count; public: Counter() : count(0) {} Counter(int c) : count(c) {} void print() {cout<<The count is <<count; } Counter operator ++ () {return Counter(++count); } }; class CountDn : public Counter { public: CountDn() : Counter() {} CountDn(int c) : Counter(c) {} void print() {cout<<The countdown is <<count; } CountDn operator-- () {return CountDn(--count); } };

  7. examples void main() { CountDn c1; Count * p_ = &c1; ++c1; c1.print(); p->print(); } The countdown is 1 The count is 1

  8. Order of Creation/Destruction • When we create subclass, the sequence of creation is • Call constructor of superclass • Call constructor of subclass • When we destroy subclass, the sequence is reverse • Call destructor of subclass • Call destructor of superclass

  9. Copying • Derived class might add extra data: Name class Person Address Class Teacher classList Office hours

  10. Copying class Employee { // … Employee & operator=(const Employee &); Employee(const Employee &); }; void f(const Manager & m) { Employee e = m; // construct e from m e = m; // assign Employee part of m to e } • Because Employee copy functions do not know anything about Managers, only the Employee part of Manager is copied. • Can be a source of surprises and errors

  11. Copying – another example Void g(Manager mm, Employee ee) { Employee* pe = &mm; // ok, Every Manager is an // Employee Manager * pm = &ee; //error: not every employee is //a Manager }

  12. Three types of inheritance • Public • class D : public B { /* … */ } • If B is a public base, its public members can be used by any function. In addition, its protected members can be used by members and friends of D and members and friends of classes derived from D. Any function can convert D* to B* • This is the most common type of inheritance

  13. Public inheritance example class Foo { public: void function1(); void function2(); }; class Test : public Foo { Public: void function3(); // test Have access to function1 and 2 }; class FooTest:public Test { Public: void function4(); // FooTest has access to function1, function2, function3 }; void main(){ FooTest t1;} // We can call functions 1, 2, 3, 4

  14. protected inheritance class Foo { public: void function1(); void function2(); }; class Test : protected Foo { Public: void function3(); // Test Have access to function1 and 2 }; class FooTest:public Test { Public: void function4(); // FooTest has access to function1, function2, function3 }; void main(){ FooTest t1; // We can call functions 3, 4

  15. Private inheritance class Foo { public: void function1(); void function2(); }; class Test : private Foo { public: void function3(); // Test Have access to function1 and 2 }; class FooTest : public Test { Public: void function4(); // FooTest has access to function3 }; void main(){ FooTest t1; // We can call functions 3, 4

  16. Private Inheritance • Private – class D : private B { /* … */ } • If B is a private base, its public and protected members can be used only by member functions and friends of D. Only friends and members of D can convert D* to a B* • Private inheritance is used to cut long chain of inheritance, and prevent further derivations

  17. Protected inheritance • Protected – class D : protected B { /* … */} • If B is a protected base, its public and protected members can be used only by member functions and friends of D and by member functions and friends of classes derived from D. Only friends and members of D and friends and members of classes derived from D can convert D* to a B*

  18. Operations in Base and Derived Classes • There are three actions that a derived class D can take with respect to an operation f() of a base class B: • The derived class can inherit the function B::f() without change • The derived class can replace B::f() by function D::f() performing different action • The derived class can extend/specialize B::f() by a function D::f() calling B::f() and performing other tasks

  19. Extending a Base Class Operation void D::f() { // Do something B::f(); // Utilize functionality from base // class // Do something }

  20. Replace and reuse Replace: Void D::f() { // Do something different } Re-use: // Do nothing D x; x.f(); // Calls B::f();

  21. Multiple Inheritance • A class can be derived from more than one base class. This is called multiple inheritance class B class A class C

  22. Syntax • class C : public A, public B { /* … */ }; • Multiple inheritance can utilize public, protected, and private inheritance types for each derived class. • Can you think of an example where multiple inheritance is useful ?

  23. Ambiguity • Suppose class A and class B both have • method print() • class C : pubic A, public B • { /* */}; • C c; • C.print(); • //which of the two is called?

  24. Resolution of Ambiguity • Use the resolution operator to specify a • particular method: • c.B::print(); • Override print() method in C to call either one or both base class methods: void C::print() { B::print(); A::print(); }

  25. Shared based class Animal Animal Horse Bird Pegasus

  26. Shared Based Class • Two separate Animal objects are created when creating an instance of class Pegasus • There is no need to have two instances of object Animal, Pegasus is-an Animal. One Animal. • We can declare virtual base classes to resolve some ambiguity when it is only caused by shared base class:

  27. Virtual Base Classes • Virtual Base will only maintain one instance of object Animal. • Virtual Base will resolve ambiguity when invoking base class methods. There is only one base, therefore there is no ambiguity • class Horse : virtual public Animal • { }; • class Bird : virtual public Animal • { }; • class Pegasus : public Horse, • public Bird • { };

  28. “Diamond” Inheritance Animal Horse Bird Pegasus

  29. Word of Advice • Use multiple inheritance in a limited way, since it adds complexity with “minor benefits” (Reiss) • It is difficult to resolve ambiguities • Inefficient • An operation of a derived class must not put an object in a state that violates an invariant of the base class. • Protected Members allow back door access for Derived class. Avoid using protected members whenever possible

  30. Polymorphism • Given a pointer of type base * ( Pointer to the Base class ), to which derived type does the object pointed to really belong ? • Four answers: • Ensure that there is no inheritance • Really? Why do we need inheritance at all ? • Place type field in the base class for the functions to inspect • Use dynamic_cast • Use virtual functions

  31. Polymorphism • Place type field in the base class for the functions to inspect class Employee { enum Empl_type {M, E}; Employee() : type(E) { } }; class Manager : public Employee { Manager() { type = M; } }; void print(Employee * emp) { switch(emp->type) { case Employee::E: cout << “Employee” << endl; break; case Employee::M: cout << “Manager” << endl; } }

  32. Polymorphism • Do you see a problem with this approach? • Adding new derived class will require extensive modifications, which can easily introduce errors • Each Derived class must know that this technique must be implemented. Why do you need to know this??? • Are you sue that enum/switch is the best way to implement this strategy. • Performance and memory usage can become unacceptable when there are a lot of derived classes.

  33. Virtual functions • Another alternative to solve this problem is to use virtual functions • Virtual functions overcome the problems with the type-field solution by allowing the programmer to declare functions in a base class that can be ( or must be in case of purely virtual functions )redefined in each derived class • Let the compiler worry about using the right function.

  34. Example of virtual function class Employee { public: // NOTE: must use keyword ‘virtual’ to make function virtual virtual void print() const { cout << “Employee” << endl; } }; class Manager : public Employee { public: // NOTE: keyword ‘virtual’ is optional, but signature must // exactly match as in base virtual function virtual void print() const { cout << “Manager” << endl; } };

  35. Example of virtual function void print(const Employee * emp) { // Depending on the run time binding, the program will call appropriate // function: Either Employee::print() or Manager::print() emp->print(); } int main() { Employee * emp1 = new Employee(); Employee *emp2 = new Manager(); print(emp1); print(emp2); } Output: Employee Manager

  36. Example of virtual function • So how does the print() function knows if it deals with Employee class or a manager class? • Call Employee * emp1 = new Employee(); Performs dynamic ( run time ) binding of virtual function print(), that is, emp1 pointing to Employee object is BINDED to use Employee::print() Employee *emp2 = new Manager(); On the other hand, during run time, emp2 pointing to Manager object is BINDED to use Manager::print() function So when we invoke emp1->print() // execute Employee::print() emp2->print() // execute Manager::print()

  37. Benefit of virtual functions • The main benefit that virtual functions brings to the programmer is to manage ALL objects in a class hierarchy with only ONE pointer. • A virtual function acts as an interface for derived class • The compiler ensures that the right function for the given object is invoked in each case • Virtual functions are most powerful help to the programmer when used with pointers to objects

  38. How does it really work? Virtual table pointer P Virtual Table //All virtual //functions //pointers virtual print() Object Employee::print() OR Manager::print()

  39. Virtual table • During compile time, all virtual function entries are placed in the virtual table. • But only during the run time (dynamic binding) those entries are filled with pointers/offset to the real functions • Pointers in virtual table that point to virtual members are offsets, which do not depend on object’s location in memory. • A pointer to a virtual member can therefore be safely passed between different address spaces as long as the same object layout is used in both

  40. Virtual Table Advantages • Can you see why virtual table has more advantages over previous methods? • Gives less chance to the programmer to make a mistake, and allow programmer concentrate on other things • Most likely virtual table is much faster than anything programmer may design • Uses hash tables, and fixed offsets. Only a matter of doing de-referencing arrays. Performance is almost O(1)

  41. Abstract Classes • So far we only looked at the concreteclasses. Concrete classes can be instantiated by themselves. • Abstract classes can not be instantiated by themselves. • Some classes, such as class Shape, represent abstract concepts for which objects cannot exist. • Abstract class only make sense as the base of some class derived from it.

  42. Abstract Classes • Some of the methods in Abstract class can not possibly provide meaningful definitions for virtual functions. • How do you define this method ? virtual void Shape :: draw() const { // ??? } • Shape class is to abstract. Circle is-a shape, Square is-a shape, polygon is-a shape • How many other shapes are there?

  43. Abstract Classes • We can not give any meaningful definition to the method Shape::draw() because: • We do not know how many possible Derived classes ( Triangle, Square, Circle, and etc ) will inherit from class Shape • Depending on the nature of each figure, draw() method has to perform completely different functionality

  44. Abstract Classes • We do not want to define any functionality for Shape::draw() method • We want to force all the derived classes ( Circle, Triangle, and etc ) to define draw() function • We call such function pure virtualfunction class Shape { // … virtual void draw()=0; };

  45. Pure virtual functions and Abstract classes • If a class has at least one pure virtual function, the class automatically becomes Abstract class. • A pure virtual function that is not defined in a derived class remains a pure virtual function, so the derived class is also an abstract class int main(){ Shape x; // Compiler error, can’t create an instance of // abstract class return 0; }

  46. Pure virtual functions • Compiler forces the designer of a derived class to implement (define) all the pure virtual functions that are in base (abstract class). • You will get a compiler error if you forget to do so • Better have a compile time checking than unexpected surprises at a run time.

  47. More on binding • Employee * pe = new Manager(“Joe User”); • Allocates object manager in memory, but our view is limited only to Employee. pe Employee Manager

  48. More on binding • What happens when the programmer tries to delete a “pe” pointer? • delete pe; • This will only de-allocate attributes of the Employee object, keeping Manager’s attributes dangling in the memory. Lost Memory! • The problem can be solved by declaring base class Destructor to be virtual

  49. Virtual Destructor • By declaring destructor virtual we guarantee that destructor of the derived class will be executed before executing destructor of the base class class Employee{ virtual ~Employee() {cout<<“~Employee\n”;} // … }; class Manager : public Employee { virtual ~Manager() { cout<<“~Manager\n”; } };

  50. Virtual destructors delete pe; Output: ~Manager ~Employee • Note, in case of virtual destructors we preserve proper cleanup even when we only have base class pointer

More Related