170 likes | 294 Views
Inheritance and Polymorphism. CS351 – Programming Paradigms. Dynamic Method Binding. Inheritance in OOP opens up many interesting properties. One of the main advantages of inheritance is that some derived class D has all of the members of its base class B .
E N D
Inheritance and Polymorphism CS351 – Programming Paradigms
Dynamic Method Binding • Inheritance in OOP opens up many interesting properties. • One of the main advantages of inheritance is that some derived class D has all of the members of its base class B. • Once D is not hiding any of the public members of B, then it is possible for an object of D to represent B in any context where a B could be used. • This feature is known as subtype polymorphism. • Lets illustrate an example:
An Example of Dynamic Binding class person { … void person :: print() { // prints details for the person } }; class student : public person { … void student :: print () { //adds more specific information } }; class lecturer : public person { … void lecturer :: print () { //adds more details } }; … student *s = new student (); lecturer *t = new lecturer (); s -> print (); t -> print (); person *x = s; person *y = t; x -> print () ; y -> print () ; This is a polymorphic call
Example cont… person *x = s; person *y = t; x -> print () ; y -> print () ; • Does the choice of the method to be called depend on the types of x and y ? • If so then this is known as static binding. • Does the choice of the method to be called depend on the classes of the objects s and t to which those variables refer ? • If so then is known as dynamic binding. • Dynamic binding is central to OOP and ensures that even if we are using the base class to refer to a child class, the correct methods will always be called.
Virtual Methods • C++ uses static binding by default. • Hence we must explicitly state that we wish to use dynamic binding. • To do this we can use the virtual keyword. • By changing the code in the previous example to look like this: class person { … virtual void print () { // print person details } }; • With virtual methods, calls are dispatched to the appropriate implementation at runtime, based upon the class of the object.
Abstract Classes • If a method is to be over-ridden by each child class, we can enforce this policy through the use of abstract classes. • An abstract class allows method headers to be declared without any implementation. • The keyword abstract is used in Java to indicate this but there is no such keyword in C++. • We must use what is known as a pure virtual specifier in C++. • To change the print method from our previous example to an abstract method, we use the following syntax: class person { … virtual void print () = 0; };
Abstract Classes cont… • If a class contains at least one abstract method, then the entire class is abstract. • This means that it is impossible to create instances of that class. • The sub-classes must provide an implementation of the abstract class and the abstract method provides a ``clue’’ for dynamic method binding. • Classes that contain abstract methods are known as interfaces. • An appropriate scheme for dynamic method binding must be used.
Multiple Inheritance • Sometimes it is desirable for a derived class to inherit features from more than one base class. • Multiple inheritance appears in C++ and Python amongst other languages. • The syntax for multiple inheritance in C++ looks like: class student : public person, public college { … } • In this case the student derives from two parent classes, person and college. • Multiple inheritance introduces a number of complicated issues.
Multiple Inheritance Issues • If two parent classes provide a method with the same name, which one does the child use? • If two parent classes are both derived from some common grandparent class, does the grandchild have one copy or two of the grandparents fields? • There are a number of modes of operation for multiple inheritance: • Multiple inheritance with a common grandparent is known as repeated inheritance. • Repeated inheritance with separate copies of the grandparent is known as replicated inheritance while repeated inheritance with a single copy of the grandparent is known as shared inheritance. • The default in C++ is replicated inheritance.
Multiple Inheritance in C++ #include <string> using namespace std; class Student { private: string id; public: string get_id(); }; class Employee { private: string id; public: string get_id(); };
Multiple Inheritance in C++ class TeachingAssistant : public Student, public Employee { … }; Teaching Assistant maintains the attributes andthe methods associated with both base classes Student, and Employee Student Employee TeachingAssistant
Multiple Inheritance in C++ • Polymorphic Assignment TeachingAssistant * M = new TeachingAssistant; Employee * E = M; //Legal as a Teaching Assistant is-an Employee Student * S = M; //Legal as a Teaching Assistant is-a Student
Problems with Multiple Inheritance • Semantic ambiguities due to identical names in the parent classes. • Similar names can be used for different operations in the base classes. • E.g. an employee might have an id_number and a student might also have an id_number field. • Both base classes might have a similar get_id() method. • It is impossible to determine which version to use in the TeachingAssistant class: the get_id() in the Employee class or the get_id () in the Student class. • E.g. TeachingAssistant * M; M -> get_id(); /*Which classes method will this refer to dynamically? */
Problems with Multiple Inheritance Solution 1: Use a fully qualified function name: TeachingAssistant * M = new TeachingAssistant; M -> Employee::get_id();
Problems with Multiple Inheritance Solution 2: Redefine the ambiguous function in the new class and hide the qualified name in a method body: class TeachingAssistant : public Student, public Employee { public: string get_id(); string student_id(); }; string TeachingAssistant :: get_id() { return Employee :: get_id(); } string TeachingAssistant :: student_id() { return Student :: get_id(); }
Replicated Inheritance • Recall that replicated inheritance does not share the same common grandparent even if they both derive from the same grandparent! • If we have code like this in C++: class A { … }; class B : public A { … }; class C : public A { … }; /* Derives from A but it is not shared! */ class D : public B, public C { … }; … • This gives us the following situation: A* a; B* b; C* c; D* d; a = d; //error ambiguous b = d; // ok c = d; // ok a = b; // ok a = c; // ok A A B C D
Shared Inheritance • Shared inheritance allows for the sharing of any common parent classes. • In C++ the default is replicated but shared inheritance is possible. • Consider: class A { ... }; class B : public virtual A { … }; class C : public virtual A { … }; class D : public B, public C { … }; • This creates the following scenario: A B C D