• EffectiveC++-条款39:明智而审慎地使用 private 继承


    一. 内容

    1. 对于 public 继承,条款32曾论证过是 is-a 关系。而对于 private 继承,显然并不是 is-a 的关系。

    2. 我们先看看 private 继承的意义

      • 如果 derived class 和 base class 是 private 继承,那么从 derived class 到 base class 的转换将失败
      • 由 private base class 继承而来的所有成员,在 derived class 中访问权限都将变为 private
    3. 现在让我们讨论其意义,private 继承意味着:is-implemented-in-terms-of (根据某物实现出)。private 继承可以看作纯粹是为了实现细节,它需要的不是类似 public 继承可以向外提供接口,仅仅是为了类中机能的实现。

    4. 但值得注意的是,刚刚条款38曾说,复合(composition)也可以体现这种关系。那么我们怎么取舍呢?答案很简单:尽可能使用复合,必要时才使用 private 继承。那什么时候才是必要?当需要 protected 成员或 virtual 函数的时候,因为复合的访问权限有限,而且无法覆写其方法。

    5. 其实还有一种激进情况,这种情况真是够激进的,只适用于你所处理的 class 不带任何数据时。这样的 class 不存在任何成员函数或变量。示例:

      class Empty {};
      
      class DemoWithEmpty {
      private:
          int x;
          FEmpty Empty;
      };
      
      inline void Try(){
      	DemoWithEmpty DemoWithEmpty;
          Empty Empty;
          std::cout<<sizeof(Empty)<<"\n";  //1
          std::cout<<sizeof(DemoWithEmpty)<<"\n"; //8
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14

      可以看到,一个不含任何成员的 class 的大小居然为 1。因为C++规定凡是独立对象都必须有非零大小。所以你可以发现 sizeof(Empty)的大小为 1,而且几乎所有的编译器都这样做。至于为什么含一个 int 大小的 class 是 8,这涉及到内存对齐的问题,不必详细讨论。

      或许你注意到了,独立对象才需要有非零大小,这意味着继承而来的 Empty class 大小可以不受约束:

      class FEmpty {};
      
      class DemoWithEmpty :private FEmpty{
      private:
          int x;
      };
      	
      inline void Try(){
      	DemoWithEmpty DemoWithEmpty;
          Empty Empty;
          std::cout<<sizeof(Empty)<<"\n";  //1
          std::cout<<sizeof(DemoWithEmpty)<<"\n"; //4
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13

      DemoWithEmpty 所用大小正好等于一个 int 的大小,而这种表现就是所谓的 EBO(empty base optimization)空白基类最优化。值得注意的是,EBO一般在单一继承下才可行。

    6. 尽管有这些例外情况,让我们回到根本。大部分 class 并非 empty,这很少成为你使用 private 继承的理由。只有当你面对需要访问 base class 的 protected 成员或者覆写 virtual 函数时,private 继承才被纳入考虑。当你审视完所有方案,仍然认为 private 继承是最佳方法,才使用它。

    二. 总结

    1. Private 继承意味 is-implemented-in-terms-of(根据某物实现出)。它通常比复合(composition)的级别低。但是当 derived class 需要访问 protected base class 的成员,或需要重新定义继承而来的 virtual 函数时,这么设计是合理的。
    2. 和复合(composition)不同,private 继承可以造成 empty base 最优化。这对致力于对象尺寸最小化的程序库开发者而言,可能很重要。
  • 相关阅读:
    算法-贪心+优先级队列-IPO
    mac IDEA激活 亲测有效
    信息安全工程实践笔记--Day2 暴力破解
    2022年认证杯SPSSPRO杯数学建模B题(第二阶段)唐宋诗的定量分析与比较研究求解全过程文档及程序
    VTK8.0.0编译+QT5.9.2+VS2017
    计算机毕业设计Java精准扶贫管理系统统(源码+mysql数据库+系统+lw文档)
    java基础巩固12
    DOM——文件对象模型(事件响应链、阻止冒泡和系统默认事件、事件代理、样式操作css、防抖和节流、预加载和懒加载、async,defer)
    太速科技-基于XC7Z100+灵汐KA200的图像处理类脑平台
    react经验14:动态修改第三方组件的样式
  • 原文地址:https://blog.csdn.net/m0_51819222/article/details/125888773