1 / 23

CSCI-383

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

freddien
Download Presentation

CSCI-383

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  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 Nilvalue belongs to all pointer types • C: the value0 belongs to all pointer types • C++: the typevoid* 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++ Derived y; Derived* py = &y; Base* px = py; px->f(); // Error! // Base::f is // protected py->f(); // Ok, Derived::f // is public • class Base{ • protected: • virtual void f(void); • }; • class Derived: public Base{ • public: • void f(void); • };

  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?

  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)

More Related