23
CSCI-383 Object-Oriented Programming & Design Lecture 24

CSCI-383 Object-Oriented Programming & Design Lecture 24

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

Page 1: CSCI-383 Object-Oriented Programming & Design Lecture 24

CSCI-383

Object-Oriented Programming & Design

Lecture 24

Page 2: 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

Page 3: CSCI-383 Object-Oriented Programming & Design Lecture 24

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

Page 4: CSCI-383 Object-Oriented Programming & Design Lecture 24

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

Page 5: CSCI-383 Object-Oriented Programming & Design Lecture 24

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

Page 6: CSCI-383 Object-Oriented Programming & Design Lecture 24

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

Page 7: CSCI-383 Object-Oriented Programming & Design Lecture 24

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

Page 8: CSCI-383 Object-Oriented Programming & Design Lecture 24

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

}

Page 9: CSCI-383 Object-Oriented Programming & Design Lecture 24

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

Page 10: CSCI-383 Object-Oriented Programming & Design Lecture 24

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

Page 11: CSCI-383 Object-Oriented Programming & Design Lecture 24

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(...)

Page 12: CSCI-383 Object-Oriented Programming & Design Lecture 24

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

Page 13: CSCI-383 Object-Oriented Programming & Design Lecture 24

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

Page 14: CSCI-383 Object-Oriented Programming & Design Lecture 24

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

Page 15: CSCI-383 Object-Oriented Programming & Design Lecture 24

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}

Page 16: CSCI-383 Object-Oriented Programming & Design Lecture 24

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

Page 17: CSCI-383 Object-Oriented Programming & Design Lecture 24

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

Page 18: CSCI-383 Object-Oriented Programming & Design Lecture 24

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

Page 19: CSCI-383 Object-Oriented Programming & Design Lecture 24

Co-variance is Natural & Essential

Page 20: CSCI-383 Object-Oriented Programming & Design Lecture 24

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

Page 21: CSCI-383 Object-Oriented Programming & Design Lecture 24

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);

}};

Page 22: CSCI-383 Object-Oriented Programming & Design Lecture 24

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

}

Page 23: CSCI-383 Object-Oriented Programming & Design Lecture 24

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)