广元市网站建设_网站建设公司_HTTPS_seo优化
2026/1/14 21:11:19 网站建设 项目流程

《你真的了解C++吗》No.023:私有继承的哲学——“实现基于”而非“是一种”

导言:被隐藏的继承

在 C++ 中,如果你在继承时不写访问限定符,class默认就是私有继承(Private Inheritance)。

classTimer{public:voidstart();voidtick();};classEngine:privateTimer{// Engine 并不是一个 Timer};

当你进行私有继承时,基类的所有公有成员在派生类中都会变成私有的。这意味着外界无法通过Engine调用start()。更重要的是,你无法再将Engine*隐式转换为Base*。多态在这里失效了。


一、 语义的转变:Implemented In Terms Of

私有继承并不代表“Engine 是一个 Timer”,它的真实含义是:“Engine 的实现利用了 Timer 的功能”

这在软件工程中被称为“根据某物实现出”(Implemented in terms of)。你只是想借用基类的代码逻辑,但你并不想让外界知道这两个类之间有任何关联,也不希望别人把你当成基类来对待。


二、 私有继承 vs 组合(Composition)

你可能会问:“如果只是想利用另一个类的功能,我直接把那个类作为我的成员变量(组合)不就行了吗?”

classEngine{private:Timer t;// 组合:通常更推荐这种做法};

确实,在 95% 的情况下,你应该优先使用组合。组合逻辑更清晰,耦合度更低。但私有继承在以下两个特殊场景中具有不可替代的优势:

1. 访问保护成员(Protected Members)

如果你需要利用基类的protected成员或函数,组合方式是做不到的(因为类外部无法访问protected),只有继承才能打开这扇门。

2. 重写虚函数

这是最常见的理由。如果你想利用某个类,但又必须重写它的某个虚函数(例如某种回调或通知机制),你就必须继承它。由于你又不想让外界发现这种继承关系,私有继承就是最佳选择。

3. 空基类优化(EBO)

我们在 No.017 聊过。如果你要持有一个“空类”作为工具,组合会占用 1 字节(对齐后可能变 4 字节),而私有继承可以利用 EBO 将开销降为0。这在 STL 容器管理分配器(Allocator)时被大量使用。


三、 权限的精细控制:Using 声明

私有继承后,所有的基类成员都躲起来了。但如果你觉得其中一两个函数对外界依然有用,你可以利用using关键字有选择地把它们“恢复”出来:

classEngine:privateTimer{public:usingTimer::start;// 仅仅把 start 重新暴露为 public};

四、 架构建议:不要滥用

  • 公有继承:表达的是接口继承。你承诺遵守基类的所有协议。
  • 私有继承:表达的是实现继承。你只是在“偷用”代码。

如果你发现自己只是想复用逻辑,请先考虑组合。只有当你确定需要处理虚函数、访问受保护成员或压榨内存(EBO)时,再祭出私有继承这柄利刃。


总结:低调的工具

  • 私有继承切断了**向上转型(Upcasting)**的路径,终结了多态。
  • 它是实现类内部逻辑的一种手段,而不是对外展示的身份。
  • 理解了私有继承,你才算真正理解了 C++ 如何在“复用代码”和“类型安全”之间做精细手术。

下一篇预告:继承关系通常是一棵树,但如果这棵树长歪了,出现了“两个爷爷”的情况,该怎么办?

➡️《你真的了解C++吗》No.024:菱形继承的解决方案——虚继承的内存布局。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询