【问题标题】:Why private-inheritance object allows member function cast derived* to base* but outsiders not?为什么私有继承对象允许成员函数将派生*转换为基*但外部不允许?
【发布时间】:2019-06-16 14:25:02
【问题描述】:

我正在检查一个关于私有继承的FAQ,我不太了解以下两个结论,有人可以解释一下吗?

在这两种情况下,用户(外人)都不能将 Car* 转换为 Engine* 吗?

私有继承变体允许 Car 的成员将 Car* 转换为 Engine*?

私有继承是组合的一种语法变体(AKA 聚合和/或 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”关系也可以使用 私有继承:

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 的成员将 Car* 转换为 Engine*
  • 私有继承变体允许访问基类的受保护成员
  • 私有继承变体允许 Car 覆盖 Engine 的虚函数
  • 私有继承变体使得为 Car 提供一个 start() 方法变得更简单(20 个字符与 28 个字符相比),该方法只需调用引擎的 start() 方法

【问题讨论】:

  • 遗漏了另一个区别:私有继承将强制使用 vtables。
  • @van dench 这不是必须的,基类可能没有虚函数。
  • 我很确定构造函数仍然强制使用 vtables。
  • @vandench 构造函数不强制使用 vtable,只有虚拟方法(或虚拟继承)可以。

标签: c++


【解决方案1】:

C++ 中private 关键字背后的动机是encapsulation——通过隐藏你的类的细节,编译器可以确保其他代码(在你的类自己的代码之外)不能也因此不依赖这些细节,因此编译器可以帮助您保证如果/当您将来更改这些细节时不需要修改其他代码。

在这种情况下,如果您通过私有继承派生子类,您就是在告诉编译器不应允许外部代码知道该继承。就外部代码而言,您的 Car 类和 Engine 类之间的关系不存在(除了作为他们不了解的实现细节)。另一方面,作为 Car 类的一部分的代码是“内部”代码,因此它会了解这种关系并利用它,如果它想这样做的话。这样,如果您更改了关系(例如,如果您将 Car 更改为从 Vehicle 而不是 Engine 的子类),您可能需要重写 Car 类中的一些代码,但您不会必须出去修复任何其他依赖Car 子类Engine 的代码,因为从一开始就不允许外部代码依赖这种关系。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-11
    • 2012-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多