|
|
Subscribe / Log in / New account

Object-oriented design patterns in the kernel, part 1

Object-oriented design patterns in the kernel, part 1

Posted Jun 3, 2011 22:26 UTC (Fri) by elanthis (guest, #6227)
In reply to: Object-oriented design patterns in the kernel, part 1 by daglwn
Parent article: Object-oriented design patterns in the kernel, part 1

> Multiple inheritance is very useful. If a language with inheritance doesn't have it, it has a major missing feature.

Sort of. Multiple inheritance in the C++ sense is useful simply because C++ doesn't differentiate between base classes, interfaces, and mixins. The need for multiple inheritance with multiple base classes is pretty small, and at least every example I've personally seen has been an example of bad interface design rather than a showcase for the need for MI (granted, my experience is not all-encompassing).

> Virtual base classes are trickier. They are painful, I admit, but necessary for some uses of MI. Many uses of MI don't need them at all. C++'s possible mistake was to place the decision point at the intermediate class level rather than at the "final" class level.

I will argue that if you start having intermediate classes very often at all, or a diamond tree, you're using inheritance wrong. Which most object-oriented developers do, unfortunately. A large part of this I fear is that it's simply taught wrong in schools. The classical examples of inheritance are things like Mammal->Dog, or Shape->Circle, or Vehicle->Car. These are attempts at modelling real-world "is-a" relationships inside of algorithmic data structures, which is really really wrong. It's a very long discussion to explain it in the necessary detail, and I believe Herb Sutter already did some fantastic talks on the topic (I'm having trouble Googling them though; maybe it wasn't Sutter that did them?).


to post comments

Object-oriented design patterns in the kernel, part 1

Posted Jun 3, 2011 23:32 UTC (Fri) by daglwn (guest, #65432) [Link] (1 responses)

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.)


Copyright © 2025, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds