为什么私有继承对象允许成员函数将派生的*转换为基*,而外部不能

Why private-inheritance object allows member function cast derived* to base* but outsiders not?

本文关键字:转换 派生 不能 外部 函数 对象 继承 许成员 成员 为什么      更新时间:2023-10-16

我正在查看一个关于私有继承的常见问题解答,我不太理解以下两个结论,有人能解释一下吗?

在这两种情况下,用户(外部人员)都不能将汽车*转换为发动机*

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

私有继承是组合的句法变体(AKA聚集和/或has-a)。

例如,"汽车有发动机"的关系可以用简单组成:

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
};

"汽车有发动机"的关系也可以用私人继承:

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
};

"私人继承"answers"组合"有什么相似之处?有这两种变体之间的几个相似之处:

  • 在这两种情况下,每个Car对象中都只包含一个Engine成员对象
  • 在这两种情况下,用户(外部人员)都不能将汽车*转换为发动机*
  • 在这两种情况下,Car类都有一个start()方法,该方法对包含的Engine对象调用start()

还有几个区别:

  • 如果要包含每辆车几台发动机
  • 私有继承变体可能会引入不必要的多重继承
  • 私有继承变体允许Car的成员将Car*转换为Engine*
  • 私有继承变体允许访问基类的受保护成员
  • 私有继承变体允许Car覆盖Engine的虚拟功能
  • 私有继承变体使为Car提供一个start()方法稍微简单一些(20个字符,而不是28个字符),该方法只调用Engine的start()

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

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