读书笔记《Effective C++》条款39:明智而审慎地使用private继承

如果class之间的继承关系是private,编译器不会自动将一个derived class对象转换为一个base class对象。由private base class继承而来的所有成员,在derived class中都会变成private属性,纵使它们在base class中原本是protected或public属性。

private继承意味implemented-in-terms-of(根据某物实现出)。如果你让class D以private形式继承class B,你的用意是为了采用class B内已经备妥的某些特性,不是因为B对象和D对象存在有任何观念上的关系。private继承纯粹只是一种实现技术(这就是为什么继承自一个private base class的每样东西在你的class内部是private:因为它们都只是实现枝节而已)。private继承意味只有实现部分被继承,接口部分应略去。如果D以private形式继承B,意思是D对象根据B对象实现而得,再没有其他意涵了。private继承在软件“设计”层面上没有意义,其意义只及于软件实现层面。

private继承意味implemented-in-terms-of(根据某物实现出),这个事实有点令人不安,因为条款38才刚指出复合(composition)的意义也是这样。如何在两者之间取舍?答案很简单:尽可能使用复合,必要时才使用private继承。何时必要:主要是当protected成员和/或virtual函数牵扯进来的时候。其实还有一种激进情况,那是当空间方面的厉害关系足以踢翻private继承的支柱时。

private继承主要用于“当一个意欲成为derived class者想访问一个意欲成为base class者的protected成分,或为了重新定义一个或多个virtual函数”。但这时候两个class之间的概念关系其实是is-implemented-in-terms-of(根据某物实现出)而非is-a。然而,有一种激进情况涉及空间最优化,可能会促使你选择“private继承”而不是“继承加复合”。

class不带任何数据时,这样的class没有non-static成员变量,没有virtual函数(因为这种函数的存在会为每个对象带来一个vptr),也没有virtual base class。于是这种所谓的empty class对象不使用任何空间,因为没有任何隶属对象的数据需要存储。然后由于技术上的理由,C++裁定凡是独立(非附属)对象都必须有非零大小。所以如果这样做:

class Empty {};//没有数据,所以其对象应该不使用任何内存

class HoldsAnInt {
private:
        int x;
        Empty e;
};
结果会发现sizeof(HoldsAnInt)>sizeof(int) ;一个Empty成员变量竟然要求内存。在大多数编译器中sizeof(Empty)获得1,因为面对“大小为零之独立(非附属)对象”,通常C++官方勒令默默安插一个char到空间对象内。

但是,这个约束不适用于derived class对象内的base class成分,因为它们并非独立(非附属)。如果继承Empty,而不是内含一个那种类型的对象:

class HoldsAnInt: private Empty {
private:
        int x;
};
几乎可以确定sizeof(HoldsAnInt)==sizeof(int)。这是所谓 EBO(empty base optimization;空白基类最优化)。如果你是一个程序库开发人员,而你的客户非常在意空间,那么值得注意EBO。另外还值得知道的是, EBO一般只在单一继承(而非多重继承)下才可行,通知C++对象布局的那些规则通常表示EBO无法被施行于“拥有多个base”的derived class身上。

现实中的“empty”class并不真的是empty。虽然它们从未拥有non-static成员变量,却往往内含typedef,enum,static成员变量,或non-virtual函数。STL就有许多技术用途的empty class,其中内含有用的成员(通常是typedef),包括base class unary_function和binary_function,这些是“用户自定义之函数对象”通常会继承的class。感谢EBO的广泛实践,使这样的继承很少增加derived class的大小。

复合和private继承都意味is-implemented-in-terms-of,但复合比较容易理解,所以无论什么时候,只要可以,还是应该选择复合。

当面对“并不存在is-a关系”的两个class,其中一个需要访问另一个的protected成员,或需要重新定义其一或多个virtual函数,private继承极有可能成为正统设计策略。即便如此你已经看到,一个混合了public继承和复合的设计,往往能够释出你要的行为,尽管这样的设计有较大的复杂度。“明智而审慎地使用private继承”意味,在考虑过所有其他方案之后,如果仍然认为private继承是“表现产需内两个class之间的关系”的最佳办法,这才用它。


要点:

1.private继承意味is-implemented-in-terms of(根据某物实现出)。它通常比复合(composition)的级别低。但是当derived class需要访问protected base class的成员,或需要重新定义继承而来的virtual函数时,这么设计是合理的。

2.和复合(composition)不同,private继承可以造成empty base最优化。这对致力于“对象尺寸最小化”的程序库开发者而言,可能很重要。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值