继承 — private
和 protected
继承
如何表达“private
继承”?
当您使用 : private
而不是 : public
时。例如:
class Foo : private Bar {
public:
// ...
};
“private
继承”和“组合”有什么相似之处?
private
继承是组合(又名聚合和/或 has-a)的一种语法变体。
例如,“Car
has-a Engine
”关系可以使用简单组合来表达。
class Engine {
public:
Engine(int numCylinders);
void start(); // Starts this Engine
};
class Car {
public:
Car() : e_(8) { } // Initializes this Car with 8 cylinders
void start() { e_.start(); } // Start this Car by starting its Engine
private:
Engine e_; // Car has-a Engine
};
“Car
has-a Engine
”关系也可以使用private
继承来表达。
class Car : private Engine { // Car has-a Engine
public:
Car() : Engine(8) { } // Initializes this Car with 8 cylinders
using Engine::start; // Start this Car by starting its Engine
};
这两种变体有几个相似之处:
- 在这两种情况下,每个
Car
对象中都恰好包含一个Engine
成员对象。 - 在这两种情况下,用户(外部人员)都不能将
Car*
转换为Engine*
。 - 在这两种情况下,
Car
类都有一个start()
方法,该方法调用所包含的Engine
对象的start()
方法。
也有几个区别:
- 如果您想在每辆
Car
中包含多个Engine
,则需要简单组合变体。 private
继承变体可能会引入不必要的多个继承。private
继承变体允许Car
的成员将Car*
转换为Engine*
。private
继承变体允许访问基类的protected
成员。private
继承变体允许Car
重写Engine
的virtual
函数。private
继承变体使得给Car
一个start()
方法,该方法简单地调用Engine
的start()
方法,略微简单一些(20 个字符,而 28 个字符)。
请注意,private
继承通常用于访问基类的 protected
成员,但这通常是一个短期解决方案(翻译:一个权宜之计)。
我应该选择组合还是私有继承?
能用组合时就用组合,必须用 private
继承时才用。
通常,您不希望访问太多其他类的内部,而 private
继承为您提供了这种额外的能力(和责任)。但 private
继承并非邪恶;它只是维护成本更高,因为它增加了某人更改某些内容并破坏您的代码的可能性。
private
继承的一个合法、长期用途是当您想构建一个 class
Fred
,它使用 class
Wilma
中的代码,并且 class
Wilma
中的代码需要调用您的新 class
Fred
中的成员函数。在这种情况下,Fred
调用 Wilma
中的非 virtual
函数,而 Wilma
调用(通常是纯虚函数)它自己,这些函数由 Fred
重写。这用组合来实现会困难得多。
class Wilma {
protected:
void fredCallsWilma()
{
std::cout << "Wilma::fredCallsWilma()\n";
wilmaCallsFred();
}
virtual void wilmaCallsFred() = 0; // A pure virtual function
};
class Fred : private Wilma {
public:
void barney()
{
std::cout << "Fred::barney()\n";
Wilma::fredCallsWilma();
}
protected:
virtual void wilmaCallsFred()
{
std::cout << "Fred::wilmaCallsFred()\n";
}
};
我应该将私有派生类指针转换为其基类指针吗?
通常,不应该。
从私有派生类的成员函数或友元内部,与基类的关系是已知的,并且从 PrivatelyDer*
到 Base*
(或 PrivatelyDer&
到 Base&
)的向上转换是安全的;不需要也不建议进行强制转换。
然而,PrivatelyDer
的用户应避免这种不安全的转换,因为它基于 PrivatelyDer
的私有决定,并且可能在不通知的情况下更改。
protected
继承与 private
继承有什么关系?
相似之处:两者都允许重写 private
/protected
基类中的virtual
函数,两者都不声明派生类是其基类的一种。
不同之处:protected
继承允许派生类的派生类了解继承关系。因此,您的“孙子”实际上暴露了您的实现细节。这既有好处(它允许 protected
派生类的派生类利用与 protected
基类的关系)也有成本(protected
派生类不能在不潜在破坏进一步派生类的情况下更改关系)。
Protected 继承使用 : protected
语法。
class Car : protected Engine {
public:
// ...
};
private
和 protected
继承的访问规则是什么?
以这些类为例:
class B { /*...*/ };
class D_priv : private B { /*...*/ };
class D_prot : protected B { /*...*/ };
class D_publ : public B { /*...*/ };
class UserClass { B b; /*...*/ };
所有派生类都不能访问 B
中任何 private
的内容。在 D_priv
中,B
的 public
和 protected
部分是 private
。在 D_prot
中,B
的 public
和 protected
部分是 protected
。在 D_publ
中,B
的 public
部分是 public
,B
的 protected
部分是 protected
(D_publ
是 B
的一种)。class
UserClass
只能访问 B
的 public
部分,这“隔离”了 UserClass
和 B
。
要使 B
的 public
成员在 D_priv
或 D_prot
中也为 public
,请使用 B::
前缀声明该成员的名称。例如,要在 D_prot
中使成员 B::f(int,float)
为 public
,您可以这样写:
class D_prot : protected B {
public:
using B::f; // Note: Not using B::f(int,float)
};