Upload
chad-berry
View
219
Download
0
Embed Size (px)
DESCRIPTION
Inclusion Polymorphism Inclusion, or subtype polymorphism arises from inheritance Employee E; Manager M; E.raise_salary(10); // OK M.raise_salary(10); // OK E.is_manager_of(...); // Error M.is_manager_of(...); // OK The code of the raise_salary method is polymorphic It can be applied to all subtypes (subclasses) of Employee We see that without polymorphism, inheritance makes very little sense
Citation preview
CSCI-383
Object-Oriented Programming & Design
Lecture 24
Inclusion Polymorphism Inclusion polymorphism: arising from an inclusion
relation between sets of values Most inclusion polymorphism is due to subtyping,
but not always Examples:
Built-in Pascal: the Nil value belongs to all pointer types C: the value 0 belongs to all pointer types C++: the type void* is a subtype of all pointer types
User-defined A subclass that is also a subtype
Inclusion Polymorphism Inclusion, or subtype polymorphism arises from
inheritanceEmployee E;Manager M;E.raise_salary(10); // OKM.raise_salary(10); // OKE.is_manager_of(...); // ErrorM.is_manager_of(...); // OK
The code of the raise_salary method is polymorphic It can be applied to all subtypes (subclasses) of
Employee We see that without polymorphism, inheritance
makes very little sense
Overriding (Inclusion Polymorphism) Like overloading, there are two distinct methods
with the same name. But there are differences Overriding only occurs in the context of the
parent/child relationship The type signatures must match Overridden methods are sometimes combined
together Overriding is resolved at run-time, not at compile
time
Replacement and Refinement There are actually two different ways that
overriding can be handled A replacement totally and completely replaces the
code in the parent class with the code in the child class
A refinement executes the code in the parent class, and adds to it the code in the child class
Most languages use both types of semantics in different situations. Constructors, for example, almost always use refinement
Reasons to Use Replacement There are a number of reasons to use replacement
of methods The method in the parent class is abstract, it must be
replaced The method in the parent class is a default method,
not appropriate for all situations
Downside of Replacement The downside of replacement semantics is that
there is no guarantee that the child class will have any meaning at all similar to the parent class
This goes back to the difference between subclasses and subtypes
A refinement makes this more difficult to do, since whatever the parent does is guaranteed to be part of the child. This is why most languages use refinement semantics for constructors
Simulating Refinement with Replacement In most languages the most important features of a
refinement can be simulated, even if the language uses replacement
void Parent::example(int a){cout << “in parent code\n”;
}
void Child::example(int a){Parent::example(12); // do parent codecout << “in child code\n”; // then child code
}
Constructors Use Refinement In most languages that have constructors, a
constructor will always use refinement This guarantees that whatever initialization the
parent class performs will always be included as part of the initialization of the child class
Overriding vs. Shadowing It is common in programming languages for one
declaration of a variable to shadow a previous variable of the same nameclass Silly{
private int x; // an instance variablepublic void example(int x){ // x shadows instance
int a = x+1;while(a > 3){ int x = 1; // local x shadows parameter a = a – x;}
}}
Shadowing can be resolved at compile time, does not require any run-time search
Conformance Overriding: replace method body in subclass Polymorphism: subclass is usable wherever
superclass is usable Dynamic Binding: consequence of overriding +
polymorphism Select right method body
Conformance: overriding and overriden should be equivalent
Superclassf(arg1, arg2) {
xxx
}
Subclassf(arg1, arg2) {
yyy
}
p->f(...)
Conformance and Overriding Thanks to the dynamic binding and polymorphism
combination, a client cannot tell which version of a method will be invoked
Ideally, an overriding method should be “semantically compatible” with the overridden one E.g., all versions of draw should draw the object Not well-defined Impossible to guarantee!
We must content ourselves with conformance in the following aspects Access Contract: pre- and post-conditions, thrown exceptions Signature: input and output arguments, function
result
Access Conformance All versions of a method should have the same
visibility Smalltalk: All methods are public C++: Not enforced, may lead to breaking of
encapsulation
class Base{ public:
virtual void f(void);};class Derived: public Base{ private:
void f(void);};
Derived y;
Derived* py = &y;
Base* px = py;
py->f(); // Error!
// Derived::f is
// private
px->f(); // Ok, but breaks
// encapsulation
Access Conformance The overriding method should be visible to all
components to which the overridden one is visible E.g., overriding enhancing visibility in C++
class Base{ protected:
virtual void f(void);};class Derived: public Base{ public:
void f(void);};
Derived y;
Derived* py = &y;
Base* px = py;
px->f(); // Error!
// Base::f is
// protected
py->f(); // Ok, Derived::f
// is public
Friendship and Overriding A friend base class is not necessarily a friend of the
derived classclass Derived;class Base{ friend void amigo(Derived*); protected:
virtual void f(void);};
class Derived: public Base{void f(void); // Visibility is the same, or is
it?};
amigo(Derived* p){ p->f(); // Error! Derived::f is private Base* px = p; // Simple up casting px->f(); // Ok, now the same Derived::f is accessible}
Contract Conformance Rules of contract conformance
Pre-condition: Overriding method must demand the same or less from its client
Post-condition: Overriding method must promise the same or more to its client
Exceptions: Overriding method must not throw any exceptions that the overridden doesn’t
Contracts and Inheritance in Eiffel Pre- and post-conditions are inherited They can be refined, but never replaced
Contracts and Inheritance in C++ The exception-specification (throw) list of an
overriding function must be at least as restrictive as that of the overridden function
Signature Conformance Elements of signature
Input arguments, Output arguments, Input-Output arguments, Result
No-variance: The type in signature cannot be changed
Co-variance: Change of type in the signature is in the same direction as that of the inheritance
Contra-variance: Change of type in the signature is in the opposite direction as that of the inheritance
Conformance Contra-variant input arguments Co-variant output arguments No-variant input-output arguments Co-variant return value
Type of Arguments For simplicity, we consider only input arguments Suppose that
m is a method of a base class m takes an argument of class C m is overridden by m in a derived class
What is the type of the corresponding argument of m in the derived class?
Variance Type
Argument Type
Language Example
No-variance Must be C C++
Contra-variance
C or base class thereof
Sather
Co-variance C or derived class thereof
Eiffel
Co-variance is Natural & Essential
Variance in C++ As a rule: No variance!
Exact match in signature required between Overriding method Overridden method
Relaxation: Co-variance is allowed in return value Must have reference semantics (pointer or reference) Relatively new addition (1992) Absolutely type safe Quite useful
Variance in C++class Employee{
public:virtual Employee* clone(void){
return new Employee(*this);}
};
class Manager: public Employee{public:
virtual Manager* clone(void){return new Manager(*this);
}};
Variance in C++
f(void){
Employee* e1 = new Employee;Employee* e2 = new Manager;Employee* e3;
e3 = e1->clone(); // e3 points to an Employeee3 = e2->clone(); // e3 points to a Manager
}
Conformance and # Arguments Suppose that
m is a method of a base class taking n arguments m is overridden by m in a derived class
Then, how many arguments should m in the derived class have? Exactly n: most current programming languages n or less: it does not matter which arguments are
omitted as long as naming is consistent n or more: the BETA programming language
(daughter of Simula)