06D-1 Inclusion Polymorphism Polymorphic code Polymorphic references Up- and Down- Casting Polymorphism and values Polymorphic Arrays
Inclusion Polymorphism in Context 06D-2 Polymorphism Ad hoc Universal Coercion Overloading Inclusion Sub-type Parametric Code Objects Inclusion, or subtype polymorphism arises from inheritance.
Inclusion Polymorphism and OOP In Strict Inheritance: SubclassingSubtyping 06D-3 Suppose that the function fire() expects an instance of class. Then, it will also accept an instance of class, provided that (strictly) inherits from. has everything has (in exactly the same form!) The additional operations in will not be used in fire() We say that the type is a subtype of the type. We say that the type includes the type. The polymorphism in this case is a result of subtyping, or type inclusion.
Methods are Polymorphic E; M; raise_salary 06D-4 E.raise_salary(10); // OK is_manager_of M.raise_salary(10); // OK E.is_manager_of(...); // Error M.is_manager_of(E); // OK The code of the raise_salary method is Polymorphic. It can be applied to all subtypes (subclasses) of. We see that without polymorphism, inheritance makes very little sense.
Polymorphic Objects 06D-5 All variables in Smalltalk are polymorphic. They may store instances of all classes. this is a polymorphic object. It may point to things of different subtypes at different times. A pointer to an inherited type is generated whenever an inherited method is called. In fact, all class pointers and all class references in C++ are polymorphic...
Pointers as Polymorphic Objects 06D-6 E, *pe; M, *pm; pe pm E M Rules for pointer mixing: pe = &E; // OK - Ordinary C type rules pm = &M; // OK - Ordinary C type rules pe = &M; // OK - Pointers are polymorphic! pm = &E; // Compile time error
References as Polymorphic Objects 06D-7 E M ostream& operator << ( ostream &, const & ); E; M; &eref1 = E; // OK! &eref2 = M; // OK! Reference to subobject &mref1 = E; // Compile time error! &mref2 = M; // OK! cout << E << M; // OK! Reference to subobject
Up-Casting Casting: A synonym for coercion from a derived type to the base type. Up-casting: casting pointers up the inheritance hierarchy. Up-casting of this occurs implicitly whenever an inherited method is called. raise_salary 06D-8 E; M; is_manager_of M.is_manager_of(E); // Type of this is *. // No casting occurs. M.raise_salary(10); // Type of this is * // in raise_salary. // Up casting must occur.
Down-Casting Down-Casting: casting pointers and references down the inheritance hierarchy: Must be done explicitly. Done by experts, and only in special cases. 06D-9 pe E E, *pe; M M, *pm; pe = &M; // OK: implicit upcasting. M = *pe; // Error: implicit downcasting is not allowed // explicit down casting: M = *( *)pe; // deprecated syntax M = *static_cast<*>pe; // recommended syntax // Either way, you better know what you are doing!
Safe Down-Casting RTTI: Run Time Type Identification New ANSI C++ compilers support RTTI. A programmer can add RTTI using an is_a function Messy! Given a pointer, it is possible to determine its dynamic type. Usually it is not necessary, and an indication of a bad design 06D-10 if ( *p = dynamic_cast< *>pe) { p->is_manager_of(e); } &eref = M;... &mref = dynamic_cast< &>eref; // bad_cast exception will be thrown if cast is invalid.
Value Semantics, Coercion & Polymorphism 06D-11 Polymorphism is applicable to code and variables but not to values. Coercion: translation from a value of one type to a value of a different type. Often with some loss of contents. Example: coercion from integer to real and vice versa. Inheritance in C++: defines a coercion from the derived class to the base class. The coercion is parametric! It works for all subtypes! Coercion is done by extracting the subobject.
What are Subobjects? 06D-12 class Base { //... }; class Derived: public Base { //... }; Each object of class Derived has a subobject of class Base It is possible in many cases to relate to that subobject
E M Mixing Values 06D-13 E; M; Rules for Mixing Values 1. call the (compiler generated) type casting operator from to 2. call the (compiler-defined or user-defined) to assignment operator. E = M; // OK - Valid coercion: truncation will occur. M = E; // Error - No coercion is defined. // is an but not vice-versa!
Arrays of Values 06D-14 Department[10]; Management[10]; Department and Management are not compatible in any way. In general, sizeof <= sizeof Usually, sizeof < sizeof Therefore, an array of managers (usually) occupies more space than an array of the same size of employees, and the conversion between the two is not trivial. This is just like an array of char which is not compatible at all with an array of int, although char and int are compatible in some operations.
Arrays of Pointers It is often convenient to define mixed type collections. The simplest and easiest way to do so is to use an array of pointers to the base class. 06D-15 *Department[100]; It is easy to deposit objects into the above array, however, determining the type of object that resides in a certain location requires down casting. Down casting should be used only in extremely special cases. In this common situation, what should be used instead is dynamic binding which is to be discussed in shortly.