Object Oriented Concepts - Is Multiple Inheritance Bad?



I believe that having gained experience with (multiple inheritance) MI, one should draw the distinction between design and implementation. MI is a great modeling tool which helps me to separate interfaces with different functionalities thus making the model more concise.

I prefer the possibility to directly express my design in an implementation language. For in any prototyping approach, design and implementation are interwoven, this provides best chances of insight and gains in creativity to me.

I’m gradually coming under the impression that people tend to use inheritance in places where a “using” or “containing” relationship would actually be more appropriate and natural. (I guess inheritance is “cool”, so people are always trying to fit it in.)

It looks like MI, in a real OO language (not a hybrid like C++) creates more problems than it solves. You get a lot of conflicts in the two inheritance-hierarchies ( In your two parent-hierarchies A and B, A: Which methods do you use, B: What about side-effects when a A-hierarchy method calls a B-hierarchy method, C: Who is self?), you get even more problems finding the code that will be executed (and even more problems finding alternative solution in other methods with the same name implemented in super classes). I have found myself in need of MI several times ( I have implemented mail- and database front ends for several databases/mail systems for different platforms, and wanted a DBMS/MailSys-hierarchy and a OPSys-hierarchy ) so I understand your questions.

Many of those problems come about when you are forced to multiply inherit implementation in order to get the specification. A good solution is to have two different inheritances: interface

and implementation.

Multiple inheritance of interfaces—specifying subtypes—is what people typically want MI for. Multiple inheritance of implementation happens less frequently. If you aren’t forced to carry around the implementation to get interface, then you don’t have to worry as much about such conflicts. (which may also be resolvable)

Welcome to the real world :-) Object Oriented Anything is cool, thus the term is added everywhere, the meaning changing to fit. (contrast with “client/server” which doesn’t mean what it did a year ago) Thus anything that has an entity defined as an “object” becomes object oriented. Same with inheritance - as long as someone can define reuse of behavior or code, then it’s called inheritance.

That’s a good sentiment, but it comes from the fact that you’re working in a language (C++) that confuses the subclassing and subtyping hierarchies. Subclassing and subtyping are *not* the same thing. Public and private inheritance in C++ are *not* the same as implementation and interface inheritance. Subclassing in a language like Smalltalk is *not* subtyping.

A more accurate paraphrase of Barbara Liskov’s definition of *subtyping* is that

If S is a subtype of T, then an object of type S may be used in any context where an object of type T is expected.

From C++? Didn’t think so… C++ is perfectly capable of multiple inheritance. Or do you mean that you can get into trouble quickly because of the various access levels, virtual base classes etc?

Anyway my feelings about this subject: I’m not strongly in favor of multiple inheritance but I’m also not strongly against it. In my experience there are times that I find multiple inheritance. sorely lacking in Java because I want to do things like mix-in classes. At other times I got myself into trouble with a complex multiple inheritance. class tree in C++.

I think it’s a case of “it depends.” There are places where multiple inheritance solves a real problem, and places where using it is just going to confuse the issue.

Languages that try to ban multiple inheritance quickly invent things like interfaces and mixins, so there are obviously some uses for the facility.

Some rules of thumb I like:

1. Is it a special case, like Java’s interfaces or Ruby’s mixins? If so, you’re probably on firm ground.

2. Have you thoroughly considered using composition instead of inheritance? Inheritance is vastly oversold.

3. Does the same attribute show up on two different legs you inherit from? That’s a red flag: you probably need to rethink the design.

C++ allows multiple inheritence, Java does not.

Whether multiple inheritence is bad or not is a matter of opinion. It certainly can lead to complexities if the namespaces of the superclasses overlap. To be honest, I don’t see how Java’s use of interfaces really solves that problem; it just moves it somewhere else.

Some people advocate that if you are going to use multiple inheritence, you should think of it as one “main” superclass, and the rest of them “mix-in” classes which add functions (think Decorator pattern).

On the other hand, sometimes you’ve got two orthogonal concepts that it makes sense to represent as two inheritence trees using multiple inheritence. For example, if you were classifying animals, you might have 5 subclasses of vertibrate: fish, amphibian, bird, reptile, and mammal. But, you might also want to have classes to represent modes of locomotion: swimmer, walker, and flyer. This might lead to such classes as:

class whale (mammal, swimmer)

class penguin (bird, walker, swimmer)

class bat (mammal, walker, flyer)

class flyingFish (fish, swimmer, flyer)

class flounder (fish, swimmer)

class africanSparrow (bird, walker, flyer).

whale.greatestDepth() makes sense, but bat.greatestDepth() does not. Likewise, africanSparrow.unladenAirspeed(), but not penguin.unladenAirspeed().

Is that bad programming style? If it turns out to be the simpliest way to accurately represent the objects you’re working with in the problem domain you’re trying to solve, I don’t see why it should be considered bad style.

This is an area where religious beliefs come into play. I’m sure you will find people who would recoil violently at the idea. Most of them probably grew up on Java :-)

The argument for single inheritance is that objects should only have one “is a” relationship. Penguin “is a” bird. For multiple inheritance, Penguin “is a” swimmer also. However, to keep everything clear, I would try to make sure each object has only one “is a” inheritance, and all the other inheritances are “does”, e.g., Penguin “is a” bird, “does” fly. If an object really does have two “is a” relationships, try to use two objects

I am both a human, and a customer of my bank. My computer is both an “electrical_device” and a “depreciable-asset”. It is completely natural in the real world for objects to have multiple “is-a” relationships with various other objects. Why then, should we not use multiple inheritance when modelling such relationships?

One major reason why multiple inheritance has such a bad name can be sheeted back to the brain-dead way in which C++ implements it. The other main reason is that inheritance itself, single or multiple, implementation or interface, is _way_ overrated as a code structuring technique. This is probably due to it not even being consistently defined - it seems to mean different things to different people at different times (depending on which language they’re currently working with).

IMHO, inheritance only works robustly in the face of change if you can guarantee that the potential instances of your (sub) classes form a strict proper subset (mathematically speaking) of the potential instances of their ancestor classes. afaik, which is not terribly far really ;-) , there is no OO language on earth that can _guarantee_ this subclass == subset relationship for you - you have to arrange it yourself (somehow).

Other folk have also suggested that in order to properly achieve the above, you need to follow the rule: “only abstract classes can be subclassed”. That is, if you want to create class B as a subclass of class A, and A is not already an abstract class, you should create a third class A’, which _is_ an abstract class, and have both class A and class B inherit from that. For a far better explanation of this and many other related issues I refer the interested reader to:

I thought about that when new style classes came out, and managed to convince myself that it couldn’t happen, at least with data properties. Unless trying to set the *same* attribute from the setter invoked from the property actually works? That seems like a lot of work to make it function poorly

That was a stupid sentence from me, sorry. On a lecture on software engineering I was taught that multiple inheritance was a bad thing to do, since there are problems with the resolution order which leads to badly readable code, induces errors, shows poor software design, etc. I see the point in that. Their most favorite programming language is Java which doesn’t support multiple inheritance. anyways. When writing the sentence above I was implying that multiple inheritance. in C++ propably is difficult to handle (though I never programmed much C++) and then Java, being a more modern programming language, abandoned multiple inheritance. in favour for interfaces.

There are certainly problems with multiple inheritance, but that doesn’t mean that all uses of MI are inherently evil. It is certainly worthwhile to listen to the arguments the anti-MI people make and think about the problems.

Of course, you need to be able to factor out those arguments which are language-specific from those which are more general.

Everything in C++ is difficult to handle. I don’t see anything about C++’s MI implementation which stands out as particularly worse or more complex than the rest of the class inheritance system.

That’s a complicated question, and I’m not sure I fully understand what you’re asking, but my general answer would be that your main goal should be to make the program easy for somebody else to understand (perhaps years from now, when you’re no longer around to answer questions). The number of lines of code is secondary, and speed of execution even less important.

When the whole thing is done, and you’re sure everything works, that’s the time to figure out if it’s fast enough. If it’s not, then you should start profiling things to figure out where most of the time is being spent and look there for speedups. The biggest speedups will typically come from algorithmic improvements, not from low-level optimizations like using or not using MI.

Because we (or at least I) don’t program that way.

The problem is context. Programming usually involves very specific contexts, such as accounting, image processing, or networking. Classes in those contexts can be very narrowly defined.

Humans don’t work in single contexts. We understand that a pencil is a kind of writing instrument, but it is also a kind of weapon. It depends on how you are holding it. Chairs are usually kinds of furniture, but some chairs belong more in the category of art. To make things worse [for computers], humans sometimes use terms that logically contradict. Humans are very good at contexts.

Ram said,

September 19, 2007 @ 12:49 am

Who says multiple inheritance is bad?

RSS feed for comments on this post · TrackBack URI


Leave a Comment

You must be logged in to post a comment.