条款39:明智而审慎地使用private继承
C++中public继承被视为一种“is-a”关系,private继承并不是“is-a”关系,只是is-implemented-in-terms-of关系,private继承意味着只有实现部分被继承,接口部分被略去。
下面我们来看看private继承的一些特性:
class Person{...};
class Student:private Person{...};
void eat(const Person& p);
void study(const Student& s);
Person p;
Student s;
eat(p);
eat(s);//error,因为private继承不满足“is-a”关系,编译器不会自动将子类对象还原为父类对象
1)因为private继承并不满足“is-a”关系,仅仅满足is-implemented-in-terms-of关系,private继承只是部分继承,编译器不会自动将一个derived class对象转换为一个base class对象。
2)由private base class继承而来的所有成员,在derived class中都会变成private属性,纵使它们在base class中原本是protected或者public属性。
class Timer{
public:
explicit Timer(int tickFrequency);
virtual void onTick() const;
...
};
class Widget:private Timer{
private:
virtual void onTick() const;
...
};
策略:
由于复合和private继承都满足is-implemented-in-terms-of关系,当我们面对一个“并不存在is-a关系”的两个classes,其中一个需要访问另一个的protected成员,或需要重新定义其一或者多个virtual函数,那么继承一定是必要的,单纯的复合已经无法解决了,可以采用“复合+继承”策略,同时private继承极有可能成为正统设计策略。
如果考虑过“复合+继承”策略之后,不适合我们才选用private继承。
最后让我们看一个private继承的例子,加深对上面部分的理解:
#include <iostream>
#include <string>
using namespace std;
class Base{
public:
Base(int xx) :x(xx){
}
void show(){
cout << x << endl;
}
virtual void guessWhat()const = 0;
virtual ~Base(){
}
private:
int x;
};
class Derived :private Base{
public:
Derived(int x) :Base(x){
}
virtual void guessWhat()const{
cout << "I'm so grateful for meeting you!!!" << endl;
}
void show(){
cout << "Derived::show" << endl;
Base::show();
}
};
int main(){
Derived d(10);
d.show();
d.guessWhat();
return 0;
}
运行结果:
总结:
1)private继承意味着is-implemented-in-terms-of关系,他通常比复合的级别低,但是当derived class需要访问protected base class中的成员,或者需要重新定义继承而来的virtual函数时,这么设计是合理的;
2)和复合不同,private继承可能造成empty base最优化,这对致力于“对象尺寸最小化”的程序库开发者来说,可能非常重要。