C++ 多重继承与虚继承
更新时间:2026-08-27。本文是
languages/cpp/主题高手层第 16 篇。入门篇讲过单继承,这篇处理"一个类有多个爹"的情况。C++ 是少数支持多重继承的主流语言——这是它灵活的地方,也是它复杂的来源。class C : public A, public B的布局、菱形继承的二义性、虚继承的间接层,都是新手转型高手必须跨过的坎。
本文要回答的问题
- 多重继承的对象布局长什么样?两个基类怎么"叠"在一起?
- 菱形继承(D 继承 B 和 C,B、C 都继承 A)有什么问题?
- 虚继承怎么解决菱形问题?它的代价是什么?
- 什么时候该用多重继承?"接口继承"是什么意思?
多重继承的基本布局
class A { int a; };
class B { int b; };
class C : public A, public B {
int c;
};对象 C 的内存布局:A 的子对象在最前,接着 B 的子对象,最后是 C 自己的成员。sizeof(C) ≥ sizeof(A) + sizeof(B) + sizeof(int)。

要点:多重继承就是多个基类子对象在内存里顺序排列,C* 转 B* 时指针要"偏移"到 B 子对象的位置。这个偏移是编译期常量,所以类型转换本身没有运行时开销(无虚继承时)。
菱形继承问题
class A { int a; };
class B : public A { int b; };
class C : public A { int c; };
class D : public B, public C { int d; };D 里有两份 A 的子对象——一份来自 B,一份来自 C。于是:
D d;
d.a = 1; // 二义性错误!到底是 B::A 里的 a 还是 C::A 里的 a?
菱形问题 = 二义性:公共基类的成员被复制两份,访问时不知道指哪一份。经典解决方案:虚继承。
虚继承:把公共基类"共享"成一份
class B : virtual public A { int b; }; // 虚继承
class C : virtual public A { int c; }; // 虚继承
class D : public B, public C { int d; };virtual 告诉编译器:A 在 D 里只放一份,B 和 C 共享它。
D d;
d.a = 1; // 现在合法!只有一份 A| 对比项 | 普通继承 | 虚继承 |
|---|---|---|
| 公共基类实例数 | 多份 | 一份 |
| 布局 | 子对象顺序排列 | 子对象位置不定,需 vbase 偏移表 |
| 转换代价 | 编译期常量偏移 | 运行时查表(间接层) |
| 使用场景 | 一般继承 | 菱形继承、接口继承 |
虚继承的代价:因为 A 的位置在 D 的布局里"不在固定偏移",访问 A 成员需要一层间接(类似虚函数的 vptr 机制)。虚继承不是免费的,能不用就不用。

实际工程:接口继承 vs 实现继承
工程上多重继承最常见的是接口继承——多个纯虚基类(接口),类实现它们:
class Drawable {
public:
virtual void draw() const = 0; // 纯虚接口
};
class Serializable {
public:
virtual void save() const = 0;
};
class Button : public Drawable, public Serializable {
public:
void draw() const override { /* 绘制 */ }
void save() const override { /* 保存 */ }
};Button 同时是"可绘制 + 可序列化"的,这是多重继承的正当用途。Java/C# 用 interface 表达同样概念,C++ 用"多个纯虚基类"。
| 继承类型 | 含义 | 典型用途 |
|---|---|---|
| 实现继承 | 继承实现(可复用代码) | 单继承为主 |
| 接口继承 | 继承契约(纯虚函数) | 多重继承主力 |
| 虚继承 | 共享公共基类 | 菱形问题兜底 |
工程原则:实现继承优先单继承 + 组合;多重继承留给"接口组合";虚继承尽量少用。 面向对象设计里的"组合优于继承"在多重继承场景尤其适用。
与本站性能主线衔接
- 对象布局:多重继承的指针偏移、虚继承的间接层直接影响对象布局,与 对象布局与缓存 呼应。
- 虚函数机制:继承与虚表配合,见 虚函数与多态。
- 内存占用:多重继承的对象更大、虚继承有额外指针,分析见 内存布局。
- 性能剖析:虚继承的间接访问在热路径有轻微开销,可用 perf 观察。
一句话总结
多重继承让对象在内存里"叠放多个基类子对象",菱形继承因重复基类产生二义性,虚继承用共享基类 + 间接层解决(但非免费);工程上多重继承用于"接口组合",实现继承优先单继承 + 组合,虚继承能避则避。
上一篇:lambda 捕获与状态 下一篇:C++ cast 全解