Download presentation
Presentation is loading. Please wait.
Published byChad Berry Modified over 9 years ago
1
CSCI-383 Object-Oriented Programming & Design Lecture 24
2
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
3
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
4
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
5
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
6
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
7
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
8
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 code cout << “in child code\n”; // then child code }
9
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
10
Overriding vs. Shadowing It is common in programming languages for one declaration of a variable to shadow a previous variable of the same name class Silly{ private int x; // an instance variable public 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
11
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 Superclass f(arg1, arg2) { xxx } Subclass f(arg1, arg2) { yyy } p->f(...)
12
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
13
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
14
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
15
Friendship and Overriding A friend base class is not necessarily a friend of the derived class class 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 }
16
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
17
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
18
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-varianceMust be C C++ Contra- variance C or base class thereof Sather Co-variance C or derived class thereof Eiffel
19
Co-variance is Natural & Essential
20
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
21
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); } };
22
Variance in C++ f(void) { Employee* e1 = new Employee; Employee* e2 = new Manager; Employee* e3; e3 = e1->clone(); // e3 points to an Employee e3 = e2->clone(); // e3 points to a Manager }
23
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)
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.