Multiple Inheritance CMPS 2143
Inheritance Heart of concept of inheritance is the is-a relationship But in the real world, objects classified in multiple, mutually non-overlapping ways. ▫ spork is a fork and a spork is a spoon. ▫ We could have a piece of furniture that is a table and a chair (chable?) 2
Multiple Inheritance Combination of non-overlapping is-a relationships Or maybe a variation of it as as-a relationships ▫ A spork can be used as-a spoon and a spork can be used as-a fork But there are problems (sigh, aren’t there always?) 3
Example: Smalltalk’s class Magnitude Class Magnitude defines a protocol for objects that have measure – objects can be compared with one another Number – supports arithmetic operations 4
Complex Number A Complex Number is-a number and we can perform arithmetic operations on complex numbers Want to inherit from Number, want to do mixed-mode arithmetic, eg ( i) Problem: comparison of two complex numbers ▫ Complex numbers are not measurable 5
Inheritance Hiearchy Need an inheritance Hierarchy where ▫ Char is a subclass of Magnitude, but not Number ▫ Integer should be a subclass of both ▫ Complex should be a subclass of Number, but not of Magnitude 6
4 solutions 1.Make Complex a subclass of number, but redefine methods that compare to produce error messages 2.Flatten Inheritance Tree: Avoid inheritance altogether and redefine EVERY method in each of the classes Char, Integer, Complex, etc. 3.Use part of the inheritance hierarchy and simulate the rest ▫ Just redefine all comparison operators 4.Make the two classes Magnitude and Number independent of each other and use multiple inheritance 7
Solution 4: Multiple Inheritance 8
Problems (sigh) Inclusion of multiple inheritance causes 2 categories of problems 1.Name ambiguity (what if two classes inherited from each of a draw method?) ▫ Problem is with child, so child must solve Use fully qualified names One::draw(); vs Two::draw(); Rename/redefine/overload – BUT signatures will have to be different virtual int * draw () {One::draw();} virtual void draw(Graphics g) {Two::draw(g);} 9
Problems cont. 2.Impact on substitutability ▫ Redefinition of the method name solves the problem locally ▫ BUT NOT if we try to maintain a list of ONE of the parents ▫ Example: GraphicalObject * g = new GraphicalCardDeck(); g->draw(); //will call draw method for CardDeck if //you redefined draw in GraphicalCardDeck //to call CardDeck::draw(); 10
Solution to Problem 2 Introduce new helper classes that inherit from the parents ▫ Redefine the draw operation in each to use a method of a different name class CardDeckParent : public CardDeck { public: virtual void draw (cardDeckDraw();} virtual void cardDeckDraw() {CardDeck::draw();} }; 11
Then redefine the two new methods in the child class class GraphicalCardDeck : CardDeckParent, GraphicalObjectParent { public: virtual void cardDeckDraw() {..} virtual void goDraw() {…} }; 12
GraphicalCardDeck *gcd = new GraphicalCardDeck(); CardDeck *cd = gcd; GraphicsObject *go = gcd; cd->draw(); //executes cardDeckDraw go->draw(); //executes goDraw gcd->draw(); //compiler error, ambiguous still 13
Multiple Inheritance of Interfaces C++ and Smalltalk allow multiple inheritance of classes Java and C# do not ▫ Fake it with multiple inheritance of interfaces ▫ REUSE concept, not code! 14
Study questions Pg. 273: 1, 2, 4, 6 15