I think it's actually a strength that C++ doesn't differentiate among types of classes. It allows more flexibility and reuse. I agree with you that there should be a good case made before using MI.
How would, for example, making "mixin" a special kind of class look in the place of MI?
I'm not sure about "intermediate classes very often" part, but you certainly are correct about the diamond hierarchy. A diamond with state in the virtual base is usually poor design and causes countless headaches in constructors. A diamond without state in the virtual base (i.e. it's a pure interface) is sometimes useful.
isa inheritance is usually good design. hasa inheritance is usually bad design. For the latter, composition is almost always the way to go. If you can find examples where "isa" is the wrong thing to do, I am very interested. Myself, I tend to prefer generic code and composition to inheritance but there are obvious cases where inheritance is useful and necessary.
Object-oriented design patterns in the kernel, part 1
Posted Jun 4, 2011 0:50 UTC (Sat) by elanthis (guest, #6227)
[Link]
> How would, for example, making "mixin" a special kind of class look in the place of MI?
The closest you get to what most people would consider a mixin in C++ would be the CRTP, but it's a little gimped because you can't properly specify that the "mixin" is implementing methods in an interface that the class inherits from.
e.g., if you have class Foo that implements interface IDoStuff, a mixin SimpleDoStuff might include members and methods that implement some or all of the methods of IDoStuff. There's no direct way to do that in C++, though, and so you end up with either grotesque inheritance trees or diamond inheritance.
The only way to handle common partial implementations of interfaces in C++ is to create intermediate classes, which then results in you having a ton of intermediate classes, and you start wanting to mix different sets of then, and then you end up with either (a) an uber base object replacing the interface, making all your object bloated and over-complex, (b) a metric crapload of intermediary classes with tons of code duplication, or (c) diamond hierarchies and virtual bases and all the problems those impose.
> isa inheritance is usually good design. hasa inheritance is usually bad design. For the latter, composition is almost always the way to go. If you can find examples where "isa" is the wrong thing to do, I am very interested. Myself, I tend to prefer generic code and composition to inheritance but there are obvious cases where inheritance is useful and necessary.
We perhaps are using slightly different definitions of "is-a", as I wasn't including interface derivation in that statement. Composition is the opposite of what I consider is-a. Yay for ambiguity in computer terminology. :)
(On a related note, composition is super important. Not understanding composition is the other thing that leads to massive inheritance trees and horribly screwed up architectures. Composition isn't necessarily trivial in C++ due to a lack of language/syntax support, but it's still possible to do and do well, unlike mixins which are borderline imposssible.)