Presentation is loading. Please wait.

Presentation is loading. Please wait.

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.

Similar presentations


Presentation on theme: "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."— Presentation transcript:

1 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 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 3 Inheritance Both Student and Teacher is a person Person TeacherStudent

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

8 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 9 Copying Derived class might add extra data: Name Address class Person classList Office hours Class Teacher

10 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 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 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 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 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 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 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 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 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 19 Extending a Base Class Operation void D::f() { // Do something B::f(); // Utilize functionality from base // class // Do something }

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

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

22 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 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 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 25 Shared based class Animal HorseBird Pegasus

26 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 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 28 “Diamond” Inheritance Animal HorseBird Pegasus

29 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 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 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 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 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 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 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 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 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 38 How does it really work? P Object Virtual Table Virtual table pointer //All virtual //functions //pointers virtual print() OR Employee::print() Manager::print()

39 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 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 41 Abstract Classes So far we only looked at the concrete classes. 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 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 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 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 virtual function class Shape { // … virtual void draw()=0; };

45 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 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 47 More on binding Employee * pe = new Manager(“Joe User”); Allocates object manager in memory, but our view is limited only to Employee. Employee Manager pe

48 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 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 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

51 51 More on Binding When an object is stored in a variable, the object is said to be bound to the variable. For example: Employee e(“Joe User”); This statement binds an Employee object with name “Joe User” to the variable e. As the execution of the program progresses, other objects can be bound to e e = Employee(“Karl Schiller”); All objects bound to “e” have the same type, namely Employee

52 52 More on binding It is possible to assign an object of a derived type to “e”, but the assignment only copies the Employee sub-object into “e” e = Manager(“Carol Smith”); This forces Manager object to be truncated so it can be fit into Employee object “e”. All Manager specific attributes are lost. We can use pointers: Employee* pe = new Employee(“Susan Yen”); pe = new Manager(“Carl Johnson”);

53 53 More on binding Two pointers can share the same object: Employee* pe1 = pe; Pointers can be bounded to no object at all pe1 = 0; Binding and references References can also be bound to an object of a given class or any derived class

54 54 More on binding Fields and operations are accessed with the dot (.) operator, not with -> A reference always have to be bound to an existing object. It can not change and it can not be null When they are parameters, they are bound to the object in the call. When function exits, the binding terminates. Compare(Employe & e1, Employee & e2)

55 55 Static and Dynamic Binding The type of a variable is the static type The type of the object is the dynamic type Testing for a Type Match C++ provides the typeid() operator to find out whether a base class pointer actually points to a derived class of a certain type Shape *s; if(typeid(s) == typeid(Rectangle*)) // s points to a rectangle object else // s points to an object of some other class

56 56 static_cast The static_cast operator coverts between related types such as one pointer type to another, or floating-point type to an integral type. int *p=static_cast (new double[10]); // C style, but works fine in C++ int *p=(int *)new double[10]; static_cast is portable, and allows the compiler to apply some minimal type checking and finding dangerous conversions

57 57 Other casts reinterpret_cast Handles conversions between unrelated types such as an integer to a pointer. const_cast Removes const const Manager *m=new Manager(“Joe”); Manager * m2=const_cast (m);

58 58 Downcasting/Widening Sometimes we need to convert a base class pointer to a concrete derived class pointer to gain access to the derived class features This process is known as downcasting, or widening C++ has a built in dynamic_cast operator that performs both the test and type conversion at a run time. dynamic_cast returns back a valid pointer if the object is of the expected type and a null pointer if it is not. dynamic_cast can also work with references Requires pointer or reference to the polymorphic type

59 59 Downcasting Example Shape* s s = new Rectangle(); // or s = new Circle(); Rectangle* r = dynamic_cast (s); if ( r != 0 ) // r equals s and points to an object that is a rectangle else // s points to an object that is not Rectangle

60 60 dynamic_cast and type checking Dynamic_cast only works with polymorphic types, however the target type does not have to be polymorphic // Assume Manager derives from abstract class //Employee, and class Date has no inheritance and // no virtual functions Manager* manager = new Manager(); Date* date = new Date(); void *pd1 = dynamic_cast (manager); //ok void *pd1 = dynamic_cast (date); //error

61 61 dynamic_cast It can cast from a polymorphic virtual base class to a derived class. We can use static_cast instead, with the following consequences: Good: Works faster than dynamic cast Bad: Dangerous, we reply on programmer not making a mistake static_cast can not cast from virtual base

62 62 Upcast, narrowing Whenever we want to convert Derived class into a Base class we call this process upcasting or narrowing Upcast is safe, as long as we remember to clean up in the end. Use of virtual Destructors Employee Manager Upcast

63 63 Shallow copy If we want to copy all the entries in a container holding a collection of objects, we can copy the pointers. Such a copy is called shallow copy Shallow copies are dangerous If one object gets destroyed, the other will point to incorrect memory Concept of identity is broken, the same memory is shared by two objects

64 64 Deep Copy Polymorphism technique is well suited for making deep copies of objects Deep copy makes a true copy of the object, preserving that each object has its own independent set of data ( Object’s identity) class Shape { public: virtual Shape* clone() const=0; }; Shape* Point::clone() const {return new Point(this);} Shape * Rectangle::clone() const{return new Rectangle(this);}

65 65 Word on delete operator Shape * drawShape[100]; //… delete [] drawShape; This is incorrect, since drawShape is not an array of objects. drawShape is an array of pointers to objects Instead we need to delete each object: for(int I=0; I<100;I++) delete drawShape[I];

66 66 Virtual Constructors? We saw virtual destructors, we obviously ask “Can the constructors be virtual?” The answer is NO, to construct an object, constructor needs the exact type of the object it is to create.


Download ppt "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."

Similar presentations


Ads by Google