public继承支持is-a关系和多态,允许隐式转换、虚函数重写与dynamic_cast;private继承切断继承链,仅复用实现;protected继承使基类成员在派生类中全为protected,供子类访问但不对外暴露。

public继承:当你需要“is-a”和多态时
公有继承是唯一能自然支持“is-a”关系和多态的继承方式。它让派生类对象可以隐式转换为基类引用或指针,virtual函数重写、dynamic_cast、基类接口被外部直接调用等行为全部成立。
常见错误现象:Base* p = new Derived; 编译失败,或 p->func() 没调用到派生类重写的版本——大概率是忘了用 public 关键字,写了 class D : Base(默认是 private)。
使用场景包括:
- 图形系统中
Circle继承Shape,所有绘图函数统一通过Shape*调用 - 容器存储不同派生类对象指针,靠虚函数实现运行时多态
- 框架要求用户传入符合某接口的类,如
std::ostream的派生类需满足流操作符重载契约
private继承:当你只想复用实现,且必须切断继承链时
私有继承不是“组合的语法糖”,它有不可替代的语义:基类成员在派生类中全变为 private,派生类对象对外不可见基类任何接口,且孙类无法再访问这些成员——继承链在此终止。
立即学习“C++免费学习笔记(深入)”;
容易踩的坑:
- 误以为
class D : private B等价于组合:其实D仍能访问B的protected成员,也能继承其虚函数表布局,组合做不到这点 - 试图用
static_cast<b>(&d)</b>转换失败:编译器明确拒绝,这是设计使然,不是 bug - 后续想让
D被其他类继承并复用B功能,结果发现完全不可行——private继承已把路封死
典型用途:定制标准库组件内部行为(如某些 std::queue 实现用 private 继承 std::deque),或模板元编程中触发 SFINAE。
protected继承:中间层封装,既不暴露也不彻底封闭
保护继承把基类的 public 和 protected 成员在派生类中都变成 protected。这意味着:派生类自身可访问,派生类的子类(孙类)也可访问,但派生类对象对外完全不可见。
它填补了 public 和 private 之间的灰色地带:
- 不想让使用者直接当基类用(排除
public),又希望未来能继续扩展(排除private) - 设计一个“半成品”基类,强制下游必须再继承一层才能用,比如
StreamBuffer类只提供底层读写能力,不开放operator 等高层接口 -
protected继承后,class C : public D中,C可以调用从B继承来的函数;而private继承下,C连名字都看不到
注意:protected 继承在实际项目中较少见,多数情况要么走清晰的 public 接口继承,要么用组合+委托更可控。
选错继承方式最常导致的硬性编译错误
三种方式一旦写错,报错信息往往不指向“继承方式问题”,而是表现为访问权限异常:
-
'func' is inaccessible:本该public继承却用了private或protected,导致外部无法调用 -
'B' is an inaccessible base of 'D':尝试static_cast<b></b>或dynamic_cast<b></b>失败,根源是继承方式非public -
'f' is not a member of 'C'(其中C : public B,B : private A):孙类无法穿透私有继承链访问曾祖类成员
真正棘手的是:这些错误可能潜伏数月,直到某个新功能试图向上转型或新增派生类才暴露。比起运行时 bug,这类编译期限制更难回溯——因为代码看起来“逻辑通顺”,只是权限卡死了。


















