Effective C++: discouraging protected inheritance?
Asked Answered
W

5

22

I was reading Scott Meyers' Effective C++ (third edition), and in a paragraph in Item 32: Make sure public inheritance is "is-a" on page 151 he makes the comment (which I've put in bold):

This is true only for public inheritance. C++ will behave as I've described only if Student is publicly derived from Person. Private inheritance means something entirely different (see Item 39), and protected inheritance is something whose meaning eludes me to this day.

The question: how should I interpret this comment? Is Meyers trying to convey that protected inheritance is seldom considered useful and should be avoided?

(I've read the question Difference between private, public, and protected inheritance as well as C++ FAQ Lite's private and protected inheritance section, both of which explain what protected inheritance means, but hasn't given me much insight into when or why it would be useful.)

Wow answered 26/6, 2011 at 13:41 Comment(2)
From the sounds of it, it's not really very useful in practice I don't think. Likely scenario: It was added to the language for consistencies sake and because the access modifiers were established and it made sense to include it, not necessarily because someone thought "Yea, this would make for a great solution to problem x".Ozell
Herb Sutter also has a good article on Uses and Abuses of Inheritance where he mentions one use case of protected inheritance. See gotw.ca/publications/mill06.htm and gotw.ca/publications/mill07.htmAndroid
F
10

Some scenarios where you'd want protected:

  1. You have a base class with methods where you know you never want to expose the functionality outside, but you know will be useful for any derived class.

  2. You have a base class with members that should be logically used by any class that extends that class, but should never be exposed outside.

Thanks to multiple inheritance you can play around with base classes' inheritance type and construct a more diversed class with existing logic and implementation.

A more concrete example:

You could create a few abstract classes that follow Design Pattern logic, lets say you have:

Observer
Subject
Factory

Now you want these all to be public, because in general, you could use the pattern on anything.

But, with protected inheritance, you can create a class that is an Observer and Subject, but only protected factory, so the factory part is only used in inherited classes. (Just chose random patterns for the example)

Another example:

Lets say for example you want to inherit from a library class (not that I encourage it). Lets say you want to make you own cool extension of std::list<> or a "better" shared_ptr.

You could derive protectedly from the base class (which is designed to have public methods).
This will give you the option to use your own custom methods, use the class' logic, and pass the logic to the to any derived class.

You could probably use encapsulation instead, but inheritance follows the proper logic of IS A (or in this case IS sort of A)

Fishplate answered 26/6, 2011 at 13:49 Comment(9)
Most of these cases can be solved with a few protected functions in the base class. Like Scott Meyers says, it is hard to find any good example where you have public functions in the base class that you want to pass on to the derived classes only.Lalonde
@Bo Persson, "Most of these cases can be solved with a few protected functions in the base class", just like functions can be avoided using a few copy pastes. Most of C++ is just for ease of use. If it can be done in a long different way, it doesn't mean you shouldn't use the short clean way.Psychodiagnosis
Another (degenerate) case where protected inheritance could be useful is multiple inheritance. One or more of the base classes may have conflicting or nonstandard APIs, and you might not be able to normalize their API because of lack of control (they're from a library you don't write or control). So you might use protected inheritance to whitewash over the APIs, and not have a future problem with new APIs getting used by others before you updated your code to whitewash over them as well.Lama
Sure there are other ways to solve this, but this is a simple solution. And it helps you avoid messing with legacy code, and don't need to start changing anything existent.Fishplate
People keep forgetting that not ALL code is theirs. There's legacy code, there are library (std,boost) classes you might want to inherit. There are other programmers with other code which you can't always alter. And you definitely don't want to write another implementation to existing code.Fishplate
There's no difference between protected and public inheritance. Both give equal access to the base class.Athelstan
@HansPassant: I'm not quite sure what you meant by your generlisation, but obviously, there is some difference between protected and public inheritance. The question is whether there's a practical situation where that difference can be taken advantage of.Consolute
@HansPassant: They both give the same access to the base class from the derived class. But not the same access to anyone using the derived class.Fishplate
While other answers offer an opinion/guess as to Meyers' meaning and this one doesn't, I'm going to accept this answer because I feel it provides some insights I did not gain from the links in my question.Wow
L
6

He isn't exactly discouraging protected inheritance, he just says that he hasn't found any good use for it. I haven't seen anyone either elsewhere.

If you happen to find a couple of really useful use cases, you might have material to write a book too. :-)

Lalonde answered 26/6, 2011 at 13:58 Comment(1)
I just have found bad uses for protected inheritance while reading legacy code. I think it should be removed from the standardPutandtake
L
4

Yup, there aren't many uses for protected or private inheritance. If you ever think about private inheritance, chances are composition is better suited for you. (Inheritance means 'is-a' and composition means 'has-a'.)

My guess is that the C++ committee simply added this in because it was very easy to do and they figured, "heck, maybe someone will find a good use for this". It's not a bad feature, it doesn't do any harm, just that no one has found any real use for it yet. :P

Lent answered 26/6, 2011 at 14:8 Comment(1)
Unlike protected inheritance, private inheritance has one good use: empty base class optimisation.Gleeful
C
3

Yes and no. I myself think that protected inheritance is a bad feature too. It basicly imports all the base class's public and protected members as protected members.

I usually avoid protected members, but on the lowest levels requiring extreme efficiency with a compiler with bad link-time optimization they are useful. But everything built on that shouldn't be messing with the original base class's (data) members and use the interface instead.

What I think Scott Meyer is trying to say, is that you can still use protected inheritance if it solves a problem, but make sure to use comments to describe the inheritance because it's not semantically clear.

Cycloplegia answered 26/6, 2011 at 13:53 Comment(0)
K
2

I don't know if Meyers is advising us to refrain from using protected inheritance, but it seems you should avoid it if Meyers is on your team, because at least he won't be able to understand your code.

Unless your co-workers know C++ better than he does, you should probably also stay away from protected inheritance. Everybody will understand the alternative, i.e. using composition.

I can imagine however a case where it could make sense: You need access to a protected member in a class whose code you can't change but you don't want to expose an IS-A relationship.

class A {
protected:
  void f(); // <- I want to use this from B!
};

class B : protected A {
private:
  void g() { f(); }
};

Even in that case, I would still consider making a wrapper with public inheritance that exposes the protected base members with public methods, then compose with these wrappers.

/*! Careful: exposes A::f, which wasn't meant to be public by its authors */
class AWithF: public A {
public:
  void f() { A::f(); }
};

class B {
private:
  AWithF m_a;
  void g() { m_a.f(); }
};
Kt answered 27/6, 2011 at 15:57 Comment(1)
Very late to the party, but Meyers said that he couldn't think of useful purposes for protected inheritance - not that he wouldn't recognise it if he saw it. When put simply like this, your workaround seems like avoiding protected inheritance on principle alone, in a contrived way that I would find much more confusing - but I'm sure it would be a valid alternative in many real-life scenarios (not documented here)Lugubrious

© 2022 - 2024 — McMap. All rights reserved.