personally i think it's a great language feature: amazingly powerful and easy to use.
why do so many people recoil at the mention of it?
personally i think it's a great language feature: amazingly powerful and easy to use.
why do so many people recoil at the mention of it?
Off the top of my head I could name the infamous diamond problem.
class a {};
class b1 : public a {};
class b2 : public a {};
class c : public b1, public b2 {}; // oops, boom !
What?
I see no problem. People shy away from multiple concrete class inheritance because it can become very hard to maintain. It is quite common in several design patterns to derive from multiple abstract base classes to define objects.Code:class A { }; class B : virtual public A { }; class C : virtual public A { }; class D : public B, public C { };
As you can see this is very powerful since now you can have objects that may implement A and B's behavior differently and because they all derive from IObject they can be stored in a container. This also paves the way for abstract factories and the like.Code:class InterfaceA { public: virtual ~InterfaceA() { } virtual void DoSomethingA() = 0; }; class InterfaceB { public: virtual ~InterfaceB() { } virtual void DoSomethingB() = 0; }; class IObject { public: virtual ~IObject() { } virtual void Foo() = 0; }; class Object : public IObject, public InterfaceA, public InterfaceB { public: Object() { } virtual void DoSomethingA() { } virtual void DoSomethingB() { } virtual void Foo() { } }; class DifferentObject : public IObject, public InterfaceA, public InterfaceB { public: DifferentObject() { } virtual void DoSomethingA() { } virtual void DoSomethingB() { } virtual void Foo() { } }; class ObjectContainer { public: ObjectContainer() { } IObject * GetObject(size_t index) {return m_Objects[index];} void AddObject(IObject * pObject) {m_Objects.push_back(pObject);} private: std::vector<IObject *> m_Objects; };
But multiple inheritance, concrete or otherwise, is not bad design. GUI's often use multiple concrete inheritance where everything derives from some base with basic window functionality. Most other GUI elements are windows but then they expose behavior specific to the type of control they are.
Also the STL and stream classes use multiple concrete inheritance and do quite well.
Last edited by VirtualAce; 02-13-2009 at 07:26 PM.
"If a method in D calls a method defined in A (and does not override the method), and B and C have overridden that method differently, then from which class does it inherit: B, or C?"
http://en.wikipedia.org/wiki/Diamond_problem
Because too often it is done just to gain access to functionality of another class -- the protected keyword encourages this by creating a netherworld where subclasses can plug into functionality they may have no business accessing.
Multiple inheritance should still follow the rule of "is-a" relationships. If C inherits A and B, then casting a C* to either A* or B* should still produce an object that performs a useful function.
Java allows multiple inheritance purely through interfaces, requiring the class to implement all functionality itself, which is one step better -- you can simulate interfaces in C++ by creating pure-virtual classes.
Code://try //{ if (a) do { f( b); } while(1); else do { f(!b); } while(1); //}
Perhaps its just me, but I have never run across a real problem that required multiple inheritance to solve. It's an interestign feature of the language, but it hasn't been particularly useful to me yet.
i'm not sure MI is ever required because the functionality of this:
can always be accomplished by:Code:class b { }; class d1:b { }; class d2:b { }; class d3:d1,d2 { };
personally i think MI is cleaner and more efficient.Code:class b { }; class d1:b { }; class d2:b { }; class d3:b { d1 _d1; d2 _d2; };
Which is an exaggerated problem thanks to virtual inheritance and/or protected/private inheritance.Off the top of my head I could name the infamous diamond problem.
O_oI have never run across a real problem that required multiple inheritance to solve.
Sure, it's a nice language, but have you ever run across a real problem that required C++?
O_oi'm not sure MI is ever required [...]always be accomplished by[...]
Rubbish.
Containment isn't inheritance. Inheritance isn't containment.
If you need an object, maybe an instance of 'd3', that "is-constrainable-as" a 'd1' object and a 'd2' object, containment will do nothing for you.
Soma
While that's true, any class with multiple base classes can be repackaged as a class that contains instances of the base classes (or, in the case of abstract bases with data members, instances of objects that contain the equivalent data) and a set of member functions that act as forwarders to the contained objects and data.
Like any language feature, there are trade-offs in using MI versus an alterative. The reason many people recoil from MI isn't because MI is inherently evil. The real reason is that most people don't take the time to fully understand the trade-offs (some of the rules are moderately complex), so they use MI in an inappropriate manner, and get bitten.
Support of MI in a programming language is somewhat challenging to implement: the semantics are somewhat complex, and getting them right in a compiler takes a lot of work. In the interests of reducing compiler complexity (or complexity of semantics in the language) some programming language designers simply take the easy way out and disallow MI. If forced to defend their choice, the language designer then claims that MI is evil/complex/unnecessary/bug-ridden/unmaintainable/etc and naive programmers simply lap up that message (after all, they've tried to use it and gotten bitten because they didn't understand the trade-offs) and therefore shy away from MI.
eh - as usual absolutes don't lend themselves well to reality. most functionality of inheritance can be simulated using containment.
i suppose if d1 and d2 both introduced a virtual method that d3 overrode, then containment does not fit the bill, and one woudl have to resort to using a function pointer, which defeats convenience of virtual methods in the first place. much like containment defeats inheritance.
RUBBISH!While that's true, any class [...] contained objects and data.
I don't care how your language spells "multiple inheritance" or how you may restate, this will remain rubbish, trash, garbage, worthless, completely freaking false.
A class containing instances of other classes isn't necessarily constrainable as the classes it contains regardless of any forwarding functions you wish to create.
You have only described parametric polymorphism.
Parametric polymorphism is a fine thing. I'm a huge fan. It isn't multiple inheritance. It does not mimic multiple inheritance. It is not containment. It does not require containment.
If containment was always an alternative to multiple inheritance then you could override the relevant virtual method by deriving 'd3_d1' from 'd1', 'd3_d2' from 'd2', and containing both 'd3_d1' and 'd3_d2' in 'd3'.i suppose if [...] defeats inheritance.
Containment isn't always an alternative to multiple inheritance in exactly the same way that containment isn't always an alternative to single inheritance... and vice versa.
Soma
can an equivalent structure always be created using containment and single inheritance? probably not. i am sure that you (yes even YOU!) would be hard pressed to conceive many such situations where it cannot be done with those two techniques with enough elaboration.Originally Posted by soma
Why does it seem to be everyone's goal to remove inheritance in favor of always using a different approach? Why is it that we consistently have to have it 100% one way or 100% another way? It is my estimation that if the language provides approved constructs and your use of the construct is in line with its design then you are just using the right tool for the job. No one ever throws away a screwdriver because it isn't a good hammer.
I personally feel those that relegate themselves to this or that but not both are not very useful practical programmers. Get the job done and use the right tool or right construct for the job. What is the big deal? I will readily admit that I use multiple inheritance when the problem warrants it and aggregation when the situation warrants it. I could care less about books and other so called 'better' languages that don't offer multiple inheritance. C++ offers it, supports it, and is not removing it. Therefore, when appropriate, I will utilize it to get my projects completed. If other languages don't offer multiple inheritance, like C#, then I will find another way to solve the problem. But just because C# and Java and Billy and Bob and Moe don't offer multiple inheritance does not mean it's wrong to use it in C++. So lighten up and go program something.
Last edited by VirtualAce; 02-14-2009 at 12:00 PM.