文章目录
- 条款39:明智而审慎地使用 private 继承
- 示例 1:private 继承无隐式转换
- 示例 2:private 继承 vs 复合
- 示例 3:empty base 最优化 (EBO)
- 适用场景
- 总结
条款39:明智而审慎地使用 private 继承
private 继承 是一种特殊的继承方式,其主要特点包括:
- 无隐式转换:如果类之间的继承关系是 private,编译器不会自动将 derived class 的对象转换为 base class 的对象。
- 成员访问权限变化:由 private base class 继承而来的所有成员,在 derived class 中都会变为 private 属性,即使它们在 base class 中是 public 或 protected 的。
与 复合 (composition) 不同,private 继承还支持特定的优化,如 empty base 最优化 (Empty Base Optimization, EBO)。这是实现轻量级对象的重要技术,尤其在一些性能敏感的程序库开发中。
示例 1:private 继承无隐式转换
class Base { public:void display() const {std::cout << "Base display" << std::endl;} };class Derived : private Base { public:void show() const {display(); // Derived 可以访问 Base 的成员} };int main() {Derived d;d.show();// d.display(); // 错误:Base 的成员在 Derived 中是 private 的return 0; }
在这个例子中,Derived
从 Base
继承了 display
,但客户代码不能直接访问它,因为 private 继承使得 Base 的成员变为 Derived 的私有成员。
示例 2:private 继承 vs 复合
复合版本:
class Base { public:void display() const {std::cout << "Base display" << std::endl;} };class Derived { public:void show() const {base.display(); // 使用复合的 Base 对象}private:Base base; // 复合关系 };
private 继承版本:
class Base { public:void display() const {std::cout << "Base display" << std::endl;} };class Derived : private Base { public:void show() const {display(); // 直接访问 Base 的成员} };
两者的主要区别在于,复合关系 更适合描述 “has-a” 关系,而 private 继承 更适合描述 “is-implemented-in-terms-of” 关系。
示例 3:empty base 最优化 (EBO)
当基类为空时,private 继承可以避免不必要的内存开销。以下示例展示了 EBO 的效果:
class EmptyBase {};class Derived : private EmptyBase { public:int value; };int main() {std::cout << "Size of EmptyBase: " << sizeof(EmptyBase) << std::endl;std::cout << "Size of Derived: " << sizeof(Derived) << std::endl;return 0; }
在此例中,Derived
类继承自 EmptyBase
,但其大小可能与 int
相同。这是因为编译器可以利用 EBO 消除空基类的内存占用。
适用场景
- 复合优先:如果你只是需要实现某种功能,复合通常是更直观的选择。
- private 继承:当你需要从基类中继承实现(而非接口),或者需要利用 EBO 最优化内存布局时,可以使用 private 继承。
总结
- private 继承 适用于描述 “is-implemented-in-terms-of” 关系。
- 与复合相比,private 继承可以直接访问基类成员,但不能隐式转换为基类类型。
- 在需要优化对象尺寸时,private 继承可能优于复合,因为它可以触发 EBO。