只重写部分虚函数完全合法;基类提供默认实现时派生类可跳过,调用自动执行基类版本;纯虚函数(=0)才强制重写;签名不一致会导致隐藏而非重写,建议使用override关键字确保正确性。

只重写部分虚函数是完全合法的
基类声明了多个 virtual 函数,你不需要全部覆盖——只重写真正需要改变行为的那几个就行。C++ 不强制子类实现所有虚函数,只要基类提供了默认实现(哪怕只是空函数体),派生类不重写它,调用时就自动走基类逻辑。
不重写的虚函数会自动继承基类实现
常见误解是“不写就是纯虚函数”,其实不是:只有带 = 0 的才是纯虚函数。如果基类里是 virtual void draw() { /* 默认绘制逻辑 */ },而派生类没定义 draw(),那调用 obj.draw() 就执行基类版本。
- 基类有默认实现 → 派生类可跳过,运行时自动调用基类版
- 基类是纯虚函数(
virtual void update() = 0;)→ 派生类必须实现,否则无法实例化 - 基类是
virtual但没定义(仅声明)→ 链接错误:未定义引用vtable,因为编译器找不到该函数地址
重写时别漏掉 const 和参数类型细节
看似“只改一个函数”,但容易因签名不一致导致意外:不是重写,而是新增了一个同名函数。编译器不会报错,但多态失效。关键检查点:
- 参数类型是否完全一致(包括
const引用、右值引用等) - 返回类型是否协变(或完全相同)
- 是否加了
const限定符?基类函数是virtual int get_id() const,你写成int get_id()就不算重写 - C++11 起建议加
override关键字,比如void render() override,编译器会立刻报错提示签名不匹配
虚函数表布局不受“部分重写”影响
每个类的 vtable 是编译期确定的:基类 vtable 有多少项,派生类 vtable 就有多少项,对应位置要么填基类函数地址,要么填你重写的函数地址。不重写的函数,其 vtable 条目直接复用基类地址——没有性能损耗,也不影响对象大小。
注意:如果基类新增虚函数,而旧派生类没重新编译,可能引发 ABI 不兼容;但这是继承体系演进问题,和“只重写部分”本身无关。
最常被忽略的是:把基类非虚函数误当虚函数去“重写”,结果只是隐藏(hiding),而非多态调用。确认是不是虚函数,得看基类声明里有没有 virtual 或 = 0。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











