3.23k likes | 3.34k Views
C++ Training Datascope Lawrence D’Antonio. Lecture 8 An Overview of C++: What is Polymorphism? – Subtype Polymorphism and Inheritance. Do not multiply objects without necessity W. Occam. What is polymorphism?. Parametric. Universal. Subtype. Polymorphism. Overloading. Ad-hoc.
E N D
C++ TrainingDatascopeLawrence D’Antonio Lecture 8 An Overview of C++: What is Polymorphism? – Subtype Polymorphism and Inheritance
What is polymorphism? Parametric Universal Subtype Polymorphism Overloading Ad-hoc Coercion Different types of objects respond to the same message and use the appropriate method.
Subtype polymorphism • Subtype (or inclusion) polymorphism allows objects of a given type to be substituted for by objects of a subtype.
What is inheritance? • One class (derived/child) relies on the definition of another class (base/parent). • Single vs. multiple inheritance • A method of sharing code or sharing interface among classes. • Language may define a class tree (with single root): Java, Smalltalk • Language may define a class forest: C++
What does a child inherit? • A child class inherits all of the features of the parent except for the following: • Constructors/destructor • The assignment operator • Friend functions and classes
Access and Inheritance • The following table gives for each type of inheritance, for a member of given access in the parent class what access that member has in the child class.
Forms of inheritance • Single: Derived class has one parent • Multiple: Derived class has more than one parent. • Interface: Defines how a class may be implemented. • Mixin: A fragment of a class that is meant to be composed with another.
Three views of inheritance • Code sharing – one defined structure can be incorporated into another. • Logical relationship – one class has the relationship of generalization or specialization with respect to the other. • Type – a subtype can be created given the definition of a supertype.
Reasons for using inheritance • Code reuse – The child inherits features from the parent, hence the code doesn’t need to be rewritten. • Concept reuse – The child overrides features of the parent. No code is shared, but the semantics of the method is maintained.
Inheritance in different languages • C++ class B: public A {}; • C# class B: A {} • CLOS (defclass B (A) () )
Inheritance part 2 • Java class B extends A {} • Object Pascal type B = object(A) … end;
Inheritance part 3 • Python class B(A): def __init__ (self): … • Ruby class B < A … end
Inheritance part 4 • Eiffel class B inherit A … end • Ada type B is new A with …
Inheritance part 5 • Objective C @interface B: A … @end • Dylan define class <B> (<A>) … end class <B>
Direct vs. Indirect Base • A base class is direct if it is explicitly mentioned as a base class in the declaration of the child class. • An indirect base class is a base class that is not mentioned explicitly in the child class declaration, but is available to the child class through one of its base classes.
Example • Direct base: class A is a direct base of class B class A {}; class B: public A {};
Example • Indirect base: class A is an indirect base of class C. class A {}; class B: public A {}; class C: public B {};
Example • In this example, class A is both a direct and indirect base of class C. class A {}; class B: public A {}; class C: public A, public B {};
Constructors/Destructors • The child class either must directly call the parent’s constructor or else the parent must have a default constructor. • Base classes are initialized in the order of declaration. • Destructors are called in reverse order of the constructors.
Example class A { public: A() {} }; class B: public A { public: B() {} };
This example is valid because class A has a default constructor. The constructor for class B will, in effect, call this constructor.
Example class A { public: A(int) {} }; class B: public A { public: B() {} };
This is illegal. Since class A has a constructor A(int), this means that A will not have a default constructor written for it. Thus A’s constructor is not called by B’s constructor. This is then an error.
Example class A { public: A(int) {} }; class B: public A { public: B(): A(5) {} };
This is legal. B’s constructor explicitly calls A’s constructor.
Order of Initialization • Virtual base classes in the order of declaration. • Nonvirtual base classes in the order of declaration. • Class members are initialized in order of declaration. • The body of the constructor is then executed.
Order of Destruction • The destructor for a class object is called before destructors for members and bases are called. • Destructors for nonstatic members are called before destructors for base classes are called. • Destructors for nonvirtual bases are called before destructors for virtual base classes.
Example class Employee { std::string first_name, last_name, ssn; public: //… }; class Manager: public Employee { std::set<Employee*> group; public: short level; };
Employee: first name: last name: ssn: Manager: first name: last name: ssn: group: level:
Is-A Relationship • A Manager is a type of Employee. So any expression accepting a valid pointer or reference to a base object may accept a pointer or reference to a child object.
Example void f(const Employee & re, const Manager &rm) { std::list<Employee *> le; le.push_front(&re); le.push_front(&rm); }
Explanation • Manager “is-an” Employee. • Manager* can be used as an Employee* (likewise for references). • Employee* cannot be used as a Manager* without a cast.
Is this legal? class Employee { std::string first_name, last_name, ssn; }; class Manager: public Employee { std::set<Employee*> group; public: short level; }; void foo(Manager &m, Employee &e) { Employee *pe = &m; Manager *pm = &e; pm->level = 2; pm = static_cast<Manager*>(pe); pm->level = 2; } main() { Manager m; Employee e; foo(m,e); };
Yes and no. Employee *pe = &m; //OK, Manager is Employee Manager *pm = &e; //Not legal, Employee is not a Manager pm->level = 2; //Not legal, e doesn’t have a level pm = static_cast<Manager*>(pe); //Works because pe points to Manager m pm->level = 2; //Works because pm points to Manager m that has a //level.
Overriding • Base class class Employee { std::string first_name, last_name; public: void print() const; }; void Employee::print() const { std::cout << "Employee\n"; }
Derived class • class Manager: public Employee { • std::set<Employee*> group; • short level; • public: • void print() const; • }; • void Manager::print() const • { • Employee::print(); • std::cout << "Manager\n"; • }
What’s the output? Employee e; Manager m; Employee *pe1 = &e; Employee *pe2 = &m; Manager *pm = &m; pe1->print(); pe2->print(); pm->print(); pm->Employee::print();
Output Employee //pe1->print() Employee //pe2->print() Employee //pm->print() Manager //pm->print() Employee //pm->Employee::print()
What’s the output? class A { public: A(int x) { std::cout << "A::x = " << x << '\n'; } }; class B: public A { public: B(int x): A(x-1) { std::cout << "B::x = " << x << '\n'; } }; class C: public A, public B { public: C(int x): A(x+1), B(x-1) { std::cout << "C::x = " << x << '\n'; } }; C c(5);
Output A::x = 6 //C::A A::x = 3 //C::B::A B::x = 4 //C::B C::x = 5 //C
Slicing • In copying from a child to a parent object, only the data of the parent subobject of the child is copied.
Slicing Example class A { int x; public: A(int a): x(a) {} }; class B: public A { int y; public: B(int a, int b): A(a), y(b) {} }; main () { B b(3,4); A a = b; a = b; }
What happened? A a = b; //Calls A(const A&), //only copies b.x a = b; //Calls A::operator=(const A&) //only copies b.x
Class Hierarchy class Employee {}; //Base class class Manager: public Employee {}; class Director: public Manager {}; class Temporary {}; //Base class class Secretary: public Employee {}; class TempSec: public Temporary, public Secretary {}; class Consultant: public Temporary, public Manager {};
Temporary Employee Secretary Manager TempSec Consultant Director
Class Hierarchy Structure • A class hierarchy forms a DAG (directed acyclic graph). • The graph need not be a tree. For example, in the graph below there are two paths from D to A. A B C D
Type fields • A simple, but usually inadequate method to create polymorphism is to use type fields. • A type field is a data type (usually an enum) that is placed in the base class for functions to use.
Type field example struct Employee { enum E_type {E,M}; E_type type; Employee(): type(E) {} }; struct Manager: public Employee { Manager() { type = M; } };