views:

974

answers:

9

When I design classes and have to choose between inheritance and composition, I usually use the rule of thumb: if the relationship is "is-a" - use inheritance, and if the relationship is "has-a" - use composition.

Is it always right?

Thank you.

+1  A: 

NoYes. If the relationship is "has-a", use composition. (Added: the original version of question said "use inheritance" for both - a simple typo, but the correction alters the first word of my answer from "No" to "Yes".)

And use composition by default; only use inheritance when necessary (but then don't hesitate to use it).

Jonathan Leffler
Corrected s/inheritance/composition in the question (of course it was a typo).
Federico Ramponi
OK - I debated whether to fix it :)
Jonathan Leffler
Federico: thanks.
Igor Oks
+5  A: 

Yes and no.

The line can be blurred. This hasn't been helped by some pretty terrible examples of OO programming from the early days of OO like: Manager is an Employee is a Person.

The thing you have to remember about inheritance is: inheritance breaks encapsulation. Inheritance is an implementation detail. There's all sorts written on this subject.

The pithiest way to sum it up is:

Prefer composition.

That doesn't mean use it to the complete exclusion of inheritance. It just means inheritance is a fallback position.

cletus
Well a Manager is an Employee and an Employee _is_ a Person. What's your point ?
@Iraimbilamja: Yes, a people Manager usually is-a Employee, but this is something completely different from the Manager pattern. Unfortunately, I've seen some explanations which conflated these two meanings.
Piskvor
That is a perfect example for an explanation on WHY you should prefer composition.
Epaga
A Manager is an Employee but a Person has (zero or more) Employee roles is a MUCH better abstraction. If your objects change type (class) that's a warning sign you're doing something wrong and that's what happens if an Employee becomes a Manager. You can argue Manager is a property of Employee too
cletus
Note that the question originally said both "is a" and "has a" were inheritance - see comments to my answer. It is now corrected to match your assumed version, but 'other way round' was officially inaccurate.
Jonathan Leffler
+2  A: 

I don't think it's as simple as "is-a" vs "has-a" - as cletus said, the line can get very blurry. It's not like two people would always come to the same conclusion given just that as a guideline.

Also as cletus said, prefer composition over inheritance. To my mind, there have to be really good reasons to derive from a base class - and in particular, the base class really needs to have been designed for inheritance, and indeed for the kind of specialization you want to apply.

Beyond that - and this will probably be an unpopular idea - it comes down to taste and gut feeling. Over time I think good developers get a better sense of when inheritance will work and when it won't, but they may well find it hard to express clearly. I know I find it hard, as this answer demonstrates. Maybe I'm just projecting the difficulty onto other people though :)

Jon Skeet
Jon, where do you get this "designed for inheritance" mantra? This is the 3rd or 4th time I've heard you say this, and I just don't understand it. Do I have to buy and read your book to get this explained? Or should I just ask a question for you to answer so you get more rep for it? ;-) I'll do that
Steven A. Lowe
done - see http://stackoverflow.com/questions/453879/how-do-you-design-a-class-for-inheritance
Steven A. Lowe
+2  A: 

Inheritance doesn't always mean there is an "is-a" relationship and the lack of one doesn't always mean there isn't.

Examples:

  • If you use protected or private inheritance then you lose external substitutability, that is, as far as anyone outside of your hierarchy is concerned a Derived is not a type of Base.
  • If you override a base virtual member and change behaviour observable from someone referencing the Base, from the original Base implementation, then you have effectively broken substitutability. Even though you have a public inheritance heirarchy Derived is-not-a Base.
  • Your class can sometimes be substituitable for another without any inheritance relationship at work. For example, if you were to use templates and identical interfaces for the appropriate const member functions then an "Ellipse const&" where the Ellipse happens to be perfectly circular could be substituitable for a "Circle const&".

What i'm trying to say here is it takes a lot of thought and work to maintain an "is-a" substitutable relationship between two types whether you use inheritance or not.

+1  A: 

People often say that inheritance is an "is-a" relationship, but that can get you into trouble. Inheritance in C++ splits into two ideas: code reuse and defining interfaces.

The first says "My class is like this other class. I'll just write code for the delta between them and reuse the other implementation from the other class as much as I can."

The second depends on abstract base classes and is a list of methods the class promises to implement.

The first can be very handy, but it can also cause maintenance problems if not done well and so some people will go so far as saying you should never do it. Most people emphasize the second, using inheritance for what other languages explicitly call an interface.

John D. Cook
A: 

My rule of thumb (though not concrete) is that if I can use the same code for different classes, then I put that code into a parent class and use inheritance. Otherwise I use composition.

This causes me to write less code which is inherently easier to maintain.

Sam
I fail to see why inheritance is better at code reuse than composition is?
John Nilsson
I have done this before but now I know it's not a good idea, especially in languages that don't support multiple inheritance. What if later you need to reuse that code in a class that needs to belong in another hierarchy?
Germán
That also causes you to have more interdependencies within your codebase. While it's less code, it will end up being more complex due to the inability to analyze anything independently.
Tom
+5  A: 

If the relationship is "is-a" - use inheritance, and if the relationship is "has-a" - use composition. Is it always right?

In a sense, yes. But you must be careful not to introduce unnecessary, artificial "is-a" relationships.

For example, one may think that a ThickBorderedRectangle is-a Rectangle, which seems reasonable at first sight, and decide to use inheritance. But this situation is better described saying that a Rectangle has-a Border, which may or may not be a ThickBorder. In this case he would better prefer composition.

In the same fashion, one may think that a ThickBorder is-a special Border and use inheritance; but it's better to say that a Border has-a width, hence preferring composition.

In all these ambiguous cases, my rules of thumb are think twice and, as others advised, prefer composition over inheritance.

Federico Ramponi
One might also think that a Rectangle doesn't have anything, but rather that some RenderableThing has a Shape or something along those lines
John Nilsson
Nice examples! I wouldn't have thought of them myself, shamefully (unless I thought hard about it).
strager
+12  A: 

No - "is a" does not always lead to inheritence. A well cited example is the relationship between a square and a rectangle. A square is a rectangle, but it will be bad to design code that inherits a Square class off a Rectangle class.

My suggestion is to enhance your "is a / has a" heuristic with the Liskov Substitution Principle. To check whether an inheritence relationship complies with the Liskov Substitution Principle, ask whether clients of a base class can operate on the sub class without knowing that it is operating on a sub class. Of course, all the properties of the sub class must be preserved.

In the square / rectangle example, we must ask whether a client of rectangle can operate on a square without knowing that it is a square. All that the client must know is that it is operating on a rectangle. The following function demonstrates a client that assumes that setting the width of a rectangle leaves the height unchanged.

void g(Rectangle& r)
{
    r.SetWidth(5);
    r.SetHeight(4);
    assert(r.GetWidth() * r.GetHeight()) == 20);
}

This assumption is true for a rectangle, but not for a square. So the function cannot operate on a square and therefore the inheritence relationship violates the Liskov Substitution principle. (By the way - the example came from the linked article.)

Trumpi
Ok, it illustrates the point. But still, why would a square be mutable?
John Nilsson
Everyone has heard the square and rectangle problem, but I have never actually come across a real world example of this (I am a junior dev, so that doesn't mean much). Can you provide one?
Ed Swangren
@Ed - Example: TCP socket uses a file descriptor, so you might say it is-a file. However, most file APIs assume random access is possible (e.g. fseek). A TCP socket is also an IP socket, but no clients should be accessing the IP layer directly (let the TCP stack handle it).
Tom
I've seen a real word example where we have a Transaction class with a collection of Sources and Destinations. We subclass Withdrawal, DebitOrder, ScheduledWithdrawal, etc. but those classes constrain the Sources and Destinations to be a certain type, hence LSP is violated.
Trumpi
@John - your question highlights the fact that inheritence (as it relates to the Liskov Substitution Principle) is all about behaviour. If the square was not mutable, then there would be no problem because no client can change the width or the height.
Trumpi
I agree with Tumpi; the square/rectangle example cited is implying a problem with mutability more so than with inheritance. The is-a relationship would be well expressed by inheritance if the shape was not mutable.
Software Monkey
+1  A: 

I think John has the right Idea. Your looking at your class relationships as creating model which is what they try to get you to do when they start teaching you OOP principals. Really, your better off looking at how things function in terms the codes architecture. That is, whats the best way for other programmers (or yourself) to re-use your code without breaking it or having to look at the implementation to see what it does.

I've found that inheritance often breaks the "black box" ideal, so if information hiding is important it may not be the best way to go. I've found increasingly that inheritance is better for providing a common interface than it is for re-using components in other places.

Of course every situation is unique, and there is no correct way to make this decision, only rules of thumb.

BigSandwich