可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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.)
回答1:
Some scenarios where you'd want protected:
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.
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)
回答2:
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. :-)
回答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.
回答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
回答5:
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(); }
};