170 likes | 184 Views
This article explores the problem of determining if a Circle is a kind of Ellipse in object-oriented programming. It discusses different solutions using abstract classes, deferred methods, and pure virtual functions.
E N D
Variations on Inheritance Object-Oriented Programming 236703 Spring 2008
Circle and Ellipse Problem Is a Circle a kind-of an Ellipse? Problem: Ellipse has a scale(x, y) method, which is meaningless for Circle. Poor Options • Circle :: scale(x, y) is an error (throw an exception ) • Pitfalls: surprising clients. • Circle::scale(x, y) is • a no-op / scales both dimensions by average • Pitfalls: very difficult to document Is an Ellipse a Kind of Circle? problem:Circleshould have centre and radius methods. • How should these be defined in Ellipse? • We cannot delete methods in inheritance!
Solutions using Abstract Classes • Ellipse derived fromOval • Circle derived fromOval • scale(x, y) method ofEllipse • scale(factor) method ofCircle • Abstract (Deferred) Class: A class that can not be used for instantiation. • Abstract Superclass Rule: All superclasses must be abstract • Inheritance represents a taxonomy. • It is rare to find a set A of real objects which has a sub-set B of real objects, such that the features of elements of B are a super-set of those of the elements of A.
Deferred Methods • A concept complementing overriding: • Overriding: Reimplement a method in an inheriting class. • Deferring: Postponing implementation of a method to an inheriting class. • Terminology: • Deferred method: A method which must be implemented in an inheriting class. • Effecting a method: Implementing a deferred method. • Deferred class: A class with deferred methods. • Effected class: A class in which all deferred methods have been effected. • Usage: • Separate interface from implementation. • Different derived classes will implement the same open contract differently. • Make classes that: • can be used for inheritance • cannot be used for instantiation • are abstract...
Pure Virtual Functions in C++ class Shape { public: // ... virtualvoid rotate(int angle)= 0; virtualvoid hide() const = 0;}; • Pure Virtual Functions (PVF): A C++ terminology --- virtual member functions which require an implementation in a derived class. • Syntax: • PVFs vs. Deferred Methods: • PVFs may, but usually don’t, have an implementation. • Deferred methods may not have an implementation. • Abstract Class in C++: A class with PVFs. • Concrete Class in C++: A class which is not abstract. • Only concrete classes may have instances.
Quiz: Abstract Classes in C++ Mark all errors in the following code: • struct Vehicle { • virtual String media() const = 0; • virtualunsigned speed() const = 0; • } V, *PV; • struct LandVehicle: public Vehicle { • String media() const { return "Land";} • } L, *PL; • struct Train: public LandVehicle { • virtualunsigned speed() const { return 130; } • } T, *PT; • PV = &V; PV = &L; PV = &T; • PL = &V; PL = &L; PL = &T; • PT = &V; PT = &L; PT = &T; • Vehicle &RV1, &RV2 = L, &RV3 = T; • LandVehicle &RL1, &RL2 = L, &RL3 = T; • Train &RT1, &RT2 = L, &RT3 = T;
Pure Virtual Destructor • class Abstract {public: • virtual ~Abstract() = 0; • // ... • }; • Abstract::~Abstract() { // ... • } • Pure virtual destructor must be defined • Destructors cannot be overridden • It must be defined outside the class declarations • Just as all defined pure virtual functions • A class defining such a destructor is abstract, but this definition does not make any derived class abstract. • No need to define a destructor in any derived class to make it concrete
Java: Interfaces vs. Abstract Classes • Both specify a type • Interface • Pure specification • Contains only method specifications (abstract methods) and named constant definitions. • All data fields are public final static and all methods are public abstract • Abstract class • Method specification plus, optionally: • May contain partial or full default method implementation, instance variables, constructors • Any class with abstract methods must be an abstract class • Abstract classes do not necessarily need to have abstract methods
Final Classes & Methods • Final Method: cannot be overridden • Call can be inline • Final Class: cannot be subclassed further • Final class implies that all methods are finalized • No dynamic binding mechanism is required • Can be used for heavy optimizations. • Categorization principle: • Inherit only from abstract classes • Instantiate only final classes
Mixins • Mixin: a subclass parametric in the superclass • The problem: class C1 extends P1 { decs } class C2 extends P2 { decs } //same declarations as in C1 Drawbacks: • code duplication • inability to use H1 and H2 in a uniform way (decs is not a type)
A Mixin in C++ struct Number { int n; virtualvoid setValue(int v) { n = v; } virtualint getValue() { return n; } }; template<typename S> // Define the mixin struct Undo: S { int old; void setValue(int v) {old = getValue(); S::setValue(v); } void undo() { S::setValue(old);} }; struct UndoableNumber : Undo<Number> // Instantiate the mixin { }; int main(int, char**) { UndoableNumber u; u.setValue(1); u.setValue(2); u.undo(); cout << u.getValue(); // output: 1 }
Jam: Java with Mixins • Drawback of the C++’s mixin idiom: • The mixin class is not a type Undo* p = new UndoableNumber(); // Compiler error! • Jam – An extension of Java with mixins mixinUndo { inheritedvoid setValue(int v); inheritedint getValue(); int old; voidsetValue(intv) {old = getValue(); super.setValue(v); } void undo() {setText(lastText); } }
Jam –Mixin Instantiation class Number { int n; void setValue(int v) { n = v; } int getValue() { return n; } } class UndoableNumber = Undo extends Number{}; • mixins are types: void g(Undo u){ u.setValue(1) ; u.setValue(2) ; System.out.println(u.old) ; System.out.println(u.getValue()) ; }
Mixins : Drawbacks • Imposes total ordering class A { publicint f() { return 0; } publicint g() { return 1; } } mixin B { publicint f() { return 2; } publicint g() { return 3; } } class C = B extends A { } • Can C offer B.f() and A.g() ?! • Fragile inheritance: • Adding a method to a mixin may silently override an inherited method
MultiMethods • Most languages allow a method (identified by a name) to have multiple definitions (bodies). • Usually, the most appropriate method body is chosen at runtime depending on the dynamic type of the receiver (1st argument in the call). • Multiple Dispatch The executed method is selected by the dynamic type of one (or more) argument(s) • A Multimethod is a method that provides multiple dispatch.
Example: Binary Methods (in Java) public class Shape { public void intersect(Shape s) { // generic code for two shapes } } Shape s = new Shape(); s.intersect(new Shape()); // no problem: Shape.intersect() is invoked s = new Rectangle(); s.intersect(new Rectangle()); // two rectangles but Shape.intersect() is invoked again! public class Rectangle extends Shape { public void intersect(Rectangle s) { // more efficient code for two rectangles } }
MultiJava: Java with MultiMethods public class Shape { public void intersect(Shape s) { // generic code for two shapes } } Shape s = new Shape(); s.intersect(new Shape()); // no problem: Shape.intersect() is invoked s = new Rectangle(); s.intersect(new Rectangle()); // no problem: Rectangle.intersect() is invoked public class Rectangle extends Shape { public void intersect(Shape@Rectangle s) { // more efficient code for two rectangles } }