派生类重写虚函数时virtual非必须但建议保留,而override必须使用以确保重写正确性;省略二者易导致隐藏而非重写、多态失效等隐蔽bug。

派生类重写虚函数时 virtual 不是必须的,但强烈建议写
只要基类函数用了 virtual,该函数在所有派生类中自动保持虚函数属性——哪怕派生类声明时完全不写 virtual,它依然是虚函数,也能参与多态。但省略 virtual 会带来实际风险:
- 可读性下降:别人(或未来的你)无法一眼判断这个函数是否意在重写基类虚函数,还是独立新增的普通函数
- 重构脆弱:如果基类虚函数签名被修改(比如加了参数),而派生类没同步改、又没写
virtual,编译器不会报错,而是静默变成“隐藏”而非“重写”,多态当场失效 - C++11 后更推荐用
override替代或补充virtual,它能强制编译器校验重写关系
override 比 virtual 更关键,且必须写在派生类中
override 是 C++11 引入的显式重写标记,放在函数声明末尾(参数列表后、const/& 等限定符之后)。它不改变函数行为,但让编译器做两件事:
- 检查该函数是否真的重写了某个基类虚函数(名字、参数、const 性、返回类型协变等全匹配)
- 如果不匹配(比如拼错函数名、漏掉
const、基类函数被删了),直接编译失败,而不是悄悄隐藏 - 注意:
override只能用于派生类,不能用于基类;也不能和final冲突使用
示例:
class Base {
public:
virtual void process() const;
virtual int get_value() = 0;
};
class Derived : public Base {
public:
void process() const override; // ✅ 推荐:有 override,编译器会校验
int get_value() override final; // ✅ 同时用 override + final 也合法
void handle() override; // ❌ 编译错误:Base 中没有 handle()
};
不写 virtual 也不写 override 的后果很隐蔽
这种写法在语法上完全合法,但极易埋下运行时 bug:
- 基类函数叫
draw(int),派生类写成void draw(double)—— 因为没加override,编译器不提醒,它只是隐藏了基类函数,调用ptr->draw(42)会去匹配int版本,结果调到基类实现 - 基类把
save()改成save(const std::string& path),派生类仍保留旧版save()且无override—— 它不再重写,变成独立函数,多态链断裂 - 团队协作中,新成员可能误以为这是个全新函数,不敢动,也不敢加逻辑,导致功能长期缺失
什么时候可以不写 virtual?仅限极少数场景
只有当你明确接受以下代价时,才考虑省略:
- 该派生类是最终类(用
final修饰),且后续绝无进一步继承 - 代码极度受限(如嵌入式裸机环境对符号表体积敏感,但现代编译器基本已优化掉冗余
virtual) - 你正在维护一个 C++98 兼容代码库(
override不可用),且已建立严格的手动审查流程
现实中,绝大多数项目应统一要求:派生类重写虚函数时,**必须带 override,同时建议带上 virtual**(尤其在 C++11 之前标准仍需支持时)。这不是风格问题,而是防止多态意外失效的最小成本防御手段。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











