private 继承(effective C++ 条款40)

来源:互联网 发布:青山大禹软件 编辑:程序博客网 时间:2024/05/29 02:15

什么是private继承

我们知道,class的默认访问权限是private的,这一点同样适用于继承,如果忘记加访问权限修饰,class的默认继承方式就是private。但private继承并非要表达继承关系,而是表达 ”根据某物实现出“的概念,这一概念跟我们通常所说的组合方式(has-a)类似,也就是说,private继承关系通常也是表达了组合关系,而非继承。

private 继承的特点

  1. 继承的所有成员的访问权限都变为private。这一点的保证主要来自于private的继承权限修饰,由此,无论base class的成员由何种方式修饰,最终都将得到private限定。即使发生重写(virtual函数的重写),任何重新设定的访问限定都是无效的(例如,限定原private virtual 函数重写后的访问权限为public,事实上不会有任何作用,反而误导类的使用者)。

  2. private 不表示 “is a”的关系,因此不会发生隐式类型转换。具体有如下的例子:

class A {};class B:private A {};void func(A& a){}int main() {    A a;    B b;    func(a); // OK    func(b); // 错误,不是is a,因此 B不是A,调用失败}

private继承的上述特性还是需要注意的。

在何时使用private继承

首先,必须明确的一点是,private继承的优先级低于组合,尽量使用组合,但private继承也有一些表现优秀的使用场景:

  1. 需要重写base class的virtual函数或使用其protect成员:

这种情况下,事实上也可以用组合代替,在private限定下,重新定义一个class继承自base class,也可实现这种需求,但这里不做讨论,只需要知道实现这种需求的方法不止一种即可。在private 继承的情况下,我们就可以重写private版本的virtual函数,从而实现对base class 中该功能的重新定义(具体例子请看条款40)。这里要注意的一点是:C++允许对private的虚函数重写(条款35提到这是模板方法设计模式的一种特例),因此,在本书中提到,这也许是private继承的缺陷,按照当时C++ 03的版本,确实无法阻止子类对该private 虚函数的重写,但是 C++ 11 的final关键字可以阻止重写,这一缺陷就不复存在了,具体来讲,一个这样的写法可以避免private virtual 被重写:

class A {public:virtual void vfunc();};class B: private A {private:    virtual void vfunc() final; // C++ 11};

2 . EBO(空白基类最优化) (重要)
编译器的EBO也是一个重要的点,这个点可以帮我们引申出一个小的考点,那就是一个独立的empty的class的size到底是多少,我们知道,这个大小通常为1,因为C++规定独立对象都必须有非零大小,因此编译器会安插一个char到该类中,所以size的结果为1.我们必须明确的一点,我们认为只要不包含non-static成员的类都可视作empty class,包括那些包含typedef以及static成员的类。
EBO是指,在发生单一继承关系时,empty class所占的空间1会被忽略。对于多继承,并不适用,此外,并不限定在private继承。

class A{};class B:private A{int x;};sizeof(A) = 1, sizeof(B) = 4; // 继承发生EBO

EBO被广泛使用在STL库中。

总结

  1. private继承相对组合具有较低使用优先级。
  2. private继承不具备is a的关系,因此隐式类型转换不存在。
  3. 在需要重写virtual函数时使用private继承。
  4. 在EBO中使用private继承。
原创粉丝点击