违反基类约定的派生类属于语义错误,编译能过但运行出bug;const/noexcept不匹配、契约违背、协变违规等均绕过override检查,导致多态行为不可预测。

违反基类使用约定的派生类,不是语法错误,而是语义错误——编译能过,运行出 bug,且难以定位。核心在于:它看起来像基类,但行为不满足基类契约。
派生类修改了虚函数的 const 性或 noexcept 规定
基类虚函数声明为 void draw() const noexcept,而派生类写成 void draw() override(缺 const 和 noexcept),这在 C++11 起就是编译错误;但如果漏掉 override,编译器会把它当普通函数隐藏基类版本,调用时可能静默回退到基类实现,或触发未定义行为。
- const 修饰符不匹配 → 破坏“只读操作”的承诺,可能让基类用户意外修改状态
- noexcept 不一致 → 若基类保证不抛异常,派生类却抛了,上层 try/catch 逻辑失效
- 加
override是唯一可靠拦截手段;不加就等于放弃编译期校验
派生类重写了纯虚函数但违背了前置条件或后置条件
比如基类注释或文档写明 virtual void set_speed(int kph) = 0; “要求 kph ≥ 0”,而派生类实现里直接接受负值并静默设为 0 —— 这不是签名错误,override 也拦不住,但它让多态调用结果不可预测。
-
override只检查语法签名,不检查语义约束 - 这种违规往往出现在接口文档模糊、测试覆盖不足的项目中
- 最典型的破窗效应:一个派生类开了口子,后续其他派生类跟着效仿,基类契约形同虚设
派生类覆盖了虚函数却改变了异常规范或返回类型协变规则
C++ 允许协变返回类型(如基类返回 Base*,派生类返回 Derived*),但必须严格满足“派生类返回类型是基类返回类型的公有派生类”。若写成 Base* → void* 或 int,编译器会报错;但若误用私有继承关系或指针/引用混用,可能绕过检查。
- 返回类型不协变 → 多态调用后无法安全向下转型
- 异常规范从
noexcept改为可能抛异常 → 上层异常安全模型崩溃 - 这类问题常在模板化基类 + 复杂继承链中暴露,调试时容易误判为内存错误
真正危险的不是编译失败,而是那些 override 没拦住、文档没写清、测试没覆盖的语义断层——它们藏在虚函数表背后,只等某个深夜的线上请求把它触发出来。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











