我正在检查关于私有继承的FAQ,我不太理解以下两个结论,有人可以解释一下吗?
用户(外部用户)都无法将Car *转换为Engine *吗?
私有继承变体允许Car的成员将Car *转换为Engine *?
私有继承是组成的句法变体(AKA 聚集和/或具有-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 };
“私有继承”和“组成”有何相似之处?有 这两个变体之间有几个相似之处:
- 在两种情况下,每个Car对象中都只包含一个Engine成员对象
- 在任何情况下,用户(外部用户)都无法将Car *转换为Engine *
- 在这两种情况下,Car类都有一个start()方法,该方法在包含的Engine对象上调用start()方法。
还有一些区别:
- 如果要包含简单组成变量,则需要 每辆车几个引擎
- 私有继承变体可以引入不必要的多重继承
- 私有继承变体允许Car的成员将Car *转换为Engine *
- 私有继承变量允许访问基类的受保护成员
- 私有继承变体允许Car覆盖Engine的虚拟功能
- 私有继承变体使Car的start()方法稍微简单一些(从20个字符到28个字符),而该方法只需调用引擎的start()方法即可。
答案 0 :(得分:4)
在C ++中,private
关键字背后的动机是encapsulation -通过隐藏有关类的详细信息,编译器可以确保其他代码(在类自己的代码之外)不能并且因此不会依靠这些细节,因此编译器可帮助您确保将来/当您更改这些细节时,无需修改其他代码。
在这种情况下,如果要通过私有继承派生子类,则是在告诉编译器不应允许外部代码知道该继承。就外部代码而言,您的Car
类和Engine
类之间的关系不存在(除非它们不了解实现细节)。另一方面,属于Car
类的代码是“内幕”代码,因此它可以了解这种关系并在需要时利用它。这样,如果您更改了关系(例如,如果将Car
从Vehicle
而不是Engine
改为子类,则可能必须重写{{1}中的一些代码}类,但是您不必走出去并在其他地方依靠Car
子类Car
的事实来修复其他代码,因为外部代码从不被允许依赖于第一名。