COSC 2767 ObjectOriented Programming Haibin Zhu Ph D
COSC 2767: Object-Oriented Programming Haibin Zhu, Ph. D. Professor of CS, Nipissing University 1
More examples for Inheritance u C++ inheritance (inheritance. cpp) u C++ overloading and overriding (overinh. cpp) u ---No overloading across scopes in C++! u Java inheritance (Inherit. java) 2
Lecture 4 Subclasses, subtype and Multiple Inheritance 3
Subtype, Subclass and Substitution u The distinction between subtype and subclass is important because of their relationship to substitution. u Recall the argument that asserted a child class has the same behavior as the parent, and thus a variable declared as the parent class should in fact be allowed to hold a value generated from a child class. u But does this argument always hold true? 4
What is a type? u Type is a shorthand for specifications. u What do we mean when we use the term type in describing a programming language? u. A set of values. (The type int, for example, describes -2147483648 to 2147483647) u A set of operations. (We can do arithmetic on ints, not on booleans). u A set of properties. (If we divide 8 by 5 we are not surprised when the result is 1, and not 1. 6). u What about when we consider classes (or interfaces) as a system for defining types? 5
What is a subtype? u if A is a subclass of B, then an instance of class A may be used in any context where an instance of type B is expected; thus we say A is a subtype of B. u For example: u A=long int, B = int u S = double, T = float 6
The Definition of Subtype u So now we can better understand the concept of a subtype. A subtype preserves the meaning (purpose, or intent) of the parent. u Problem: meaning is extremely difficult to define. Think about how to define the LIFO characteristics of a stack. 7
The Problem of Defining Meanings u u u u 8 Consider how we might define a Stack ADT in Java: interface Stack { public void push (Object value); public Object top (); public void pop (); } Notice how the interface itself says nothing about the LIFO property, which is the key defining feature of a stack. Is the following a stack? class Non. Stack implements Stack { public void push (Object value) { v = value; } public Object top () { return v; } public void pop () { v = null; } private Object v = null; } Question: Can an interface be considered as a type?
Subclasses are not Necessarily Subtypes u It is easy to create a subclass that is not a subtype -- think of Non. Stack. It is also possible to create subtypes that are not subclasses. Think of Array in Smalltalk. This class is characterized by the following interface: u at: input put: value u at: int u size u But class Dictionary will also support the same interface, and perform similar actions -but Dictionary is not a subclass of Array. 9
The Substitution Paradox u u 10 There is a curious paradox that lies at the heart of most strongly typed object-oriented programming languages. Substitution is permitted, based on subclasses. That is, a variable declared as the parent type is allowed to hold a value derived from a child type. Yet from a semantic point of view, substitution only makes sense if the expression value is a subtype of the target variable. If substitution only makes sense for subtypes and not for all subclasses, why do programming languages based the validity of assignment on subclasses?
The Undecidability of the Subtype Relationship u It is trivial to determine if one class is a subclass of another. It is extremely difficult to define meaning (think of the Stack ADT), and even if you can it is almost always impossible to determine if one class preserves the meaning of another. u One of the classic corollaries of the halting problem is that there is no procedure that can determine, in general, if two programs have equivalent behavior. 11
Is This a Problem? u What does it take to create a subclass that is not a subtype? u The new class must override at least one method from the parent. u It must preserve the type signatures. u But it must violate some important property of the parent. u Is this common? Not likely. But it shows you where to look for problem areas. 12
Summary of subclasses u To say a class is a subclass of another simply asserts that it is built using inheritance. u By itself, the subclass relationship says nothing about the behavior of the child in relation to the parent. u The term subtype is used to describe a class that matches the behavior of another class. u It is easy to build subclasses that are not subtypes. It is possible (although not as easy) to build subtypes that are not subclasses. 13
u Multiple 14 Inheritance
Inheritance as Categorization u u In one sense, the process of inheritance is a form of categorization. A Text. Window is a type of Window, so class Text. Window inherits from class Window. But in the real world, most objects can be categorized in a variety of ways. The author of the textbook is u u u 15 North American Male Professor Parent None of these are proper subsets of the other, and we cannot make a single rooted inheritance hierarchy out of them.
Inheritance as Combination u Instead, real world objects are combinations of features from different classification schemes, each category giving some new insight into the whole: u Author is North American, and u Author is Male, and u Author is a Professor, and u Author is a Parent. u Note that we have not lost the is-a relationship; it still applies in each case. 16
Complex Numbers u Two abstract classifications u Magnitude - things that can be compared to each other. u Number - things that can perform arithmetic u Three specific classes u Integer - comparable and arithmetic u Char - comparable but not arithmetic u Complex - arithmetic but not comparable 17
Possible Solutions u u 18 Make Number subclass of Magnitude, but redefine comparison operators in class complex to give error message if used. (subclassing for limitation). Don't use inheritance at all - redefine all operators in all classes. (flattening the inheritance tree). Use part inheritance, but simulate others - use Number, but have each number implement all relational operators. Make Number and Magnitude independent, and have Integer inherit from both. (multiple inheritance).
Inheritance as a form of Combination 19
What is Multiple Inheritance? u If class A inherits from more than one class, i. e. A inherits from B 1, B 2, . . . , Bn, we speak of multiple inheritance. u This may introduce naming conflicts in A if at least two of its superclasses define properties with the same name. 20
Naming Conflicts u Name conflicts between superclasses of a class. u 21 If attributes or methods defined in one superclass have the same name as attributes or methods defined in another superclass.
Name Ambiguity u What happens when same name is used in both parent classes. u. A Card. Deck knows how to draw a Card. u A Graphical. Item knows how to draw an image on a screen. u A Graphical. Card. Deck should be able to draw. which? 22
B 1 {//… int x; } B 2 {//… int x; public: int get. Value(); } Ex 4 -1. cpp 23 B 3 {//… int x; public: int get. Value(); } A { } Multiple Inheritance and Naming conflicts
Conflict Conquering 1. Using the order of the superclasses u u 24 If there are more attributes or methods with the same name in different superclasses, the ones occurring in the first class in the list of superclasses are inherited. (Done by the compiler) If the order is from left to right, then x means the x of B 1, and get. Value() means the get. Value() of B 2.
Conflict Conquering 2. The user can determine u u u 25 The user can inherit conflicting attributes or methods, but he has to explicitly rename conflicting attributes or methods in the subclass. (Done by the users) B 1: : x; or B 2: : x; B 2: : get. Value(); or B 3: : get. Value();
One Solution: Redefinition u u u u u 26 To redefine or the other operation in the child class Graphical. Card. Deck : public Card. Deck, public Graphical. Object { public: virtual void draw () { return Card. Deck: : draw(); } virtual void paint () { Graphical. Object: : draw(); } } Graphical. Card. Deck *gcd; gcd->draw(); // selects Card. Deck draw gcd->paint(); // selects Graphical. Object draw
Problem with Redefinition Solution u The redefinition solution is not without cost, however. Now what happens when we run up against the principle of substitution? u Graphical. Object * g = new Graphical. Card. Deck(); u g->draw(); u // opps, doing wrong method! u This problem can be mitigated, but the solution is complex and not perfect. 27
Redefinition Class Card. Deck. Parent : Public Card. Deck { Public: Virtual void draw() {card. Deck. Draw(); } Virtual void card. Deck. Draw() {Card. Deck: : draw()} } Class Graphical. Object. Parent : Public Graphical. Object { Public: Virtual void draw() {go. Draw(); } Virtual void go. Draw() {Graphical. Object: : draw()} } 28
Redefinition Class Graphical. Card. Deck: public Card. Deck. Parent, Graphical. Object. Parent {public: Virtual void card. Deck. Draw() {…} Virtual go. Draw() {…} } Graphical. Card. Deck *gcd = new Grpahical Card. Deck(); Card. Deck *cd = gcd; Graphical. Object *go=gcd; Cd->draw(); Go-draw(); Gcd->draw(); //ex 4 -2. cpp 29
Other Approaches to Name Ambiguity u Other languages use different approaches to solving the problem of ambiguous names u Eiffel uses the ability to rename features from the parent class. A polymorphic variable accessing through the parents name will access the renamed feature in the child. u CLOS and Python resolve ambiguous names by the order in which the parent classes are listed. The first occurrence of the name found in a systematic search is the one selected. 30
Precedence conflicts We have class A with attribute a, class B which is a subclass of A and redefines attribute a, class C which is also a subclass of A, and class D which is a subclass of B and C (multiple inheritance). u Class D can inherit the redefined version of a from class B or the original version from class C. u Which version of attribute a should be inherited? u 31
Precedence conflicts class A {a; } class B: public A { } class C: public A {a; //redefined } class D: public B, C {? } 32 Diamond problem.
Conflict Conquering u The same as the naming conflicts: u Use the order of the superclasses by the compiler; u Use the explicit class name by the users 33
Virtual inheritance in C++ u In C++, virtual inheritance is a kind of inheritance that solves some of the problems caused by multiple inheritance (particularly the "diamond problem") by clarifying ambiguity over which ancestor class members to use. u The part of the object that belongs to the virtual base class becomes common direct base for the derived class and any next class that derives from it. 34
A Problem u u u 35 class Base { public: virtual void print() const = 0; }; class Derived. One : virtual public Base { public: void print() const { cout << "Derived. Onen"; } };
u u u u u 36 class Derived. Two : virtual public Base { public: void print() const { cout << "Derived. Twon"; }; } class Multiple : public Derived. One, public Derived. Two { public: void print() const { Derived. Two: : print(); } };
Solution u u u 37 u u int main() { Multiple both; // instantiate Multiple object Derived. One one; // instantiate Derived. One object Derived. Two two; // instantiate Derived. Two object // declare array of base-class pointers and initialize // each element to a derived-class type Base *array[ 3 ]; array[ 0 ] = &both; array[ 1 ] = &one; array[ 2 ] = &two; ///… } //ex 4 -3. cpp //http: //www. phpcompiler. org/doc/virtualinheritance. html
Multiple Inheritance and Composition u Wrong One! class Head {} class Engine {} class Wing{} class Tail {} class Plane: public Head, public Engine, public Wing, public Tail { } 38
Multiple Inheritance and Composition Correct One! class Plane { private: Head head; Engine engines[4]; //4 engines Wing wings[2]; //2 wings Tail tail; public: …… } u 39
Java Interfaces u u u u 40 An interface is like a class, but it provides no implementation. Later, another class can declare that it supports the interface, and it must then give an implementation. public interface Storing { void write. Out (Stream s); void read. From (Stream s); }; public class Bit. Image implements Storing { void write. Out (Stream s) { //. . . } void read. From (Stream s) { //. . . } }; We will have much more to say about interfaces later after we discuss inheritance.
Java Interfaces u Simple inheritances (extends) for classes u Multiple implementations (implements) for interfaces u Mulinterface. java 41
u u u u u 42 interface intf 1 { public void fun 1(); } interface intf 2 { public void fun 2(); } class par{ int i; public void fun() { System. out. println("Fun!"); } } public class mulinterface extends par implements intf 1, intf 2{ public void fun 1() { System. out. println("Fun 1!"); } public void fun 2() { System. out. println("Fun 2!"); } public static void main(String[] args) { mulinterface p = new mulinterface(); p. fun 1(); p. fun 2(); } }
Summary of Multiple Inheritance u Name ambiguity u Impact on substitution u The Problem of Common Ancestors 43
- Slides: 43