一眼识别override还是hiding:需同时满足父类函数virtual且子类函数签名完全一致(含const、引用限定符、参数类型);否则为hiding。

怎么一眼看出是 override 还是 hiding?
看子类函数是否满足 virtual + 签名完全一致(含 const、引用符、参数类型)这两个硬条件。不满足,就是 hiding。
常见错误现象:Base* p = new Derived(); p->func(); 调不到子类版本,但子类明明写了同名函数——大概率是签名没对齐,比如父类是 void func() const,子类写了 void func()(少 const),这就不是 override,而是 hiding。
- const 修饰符差异、&/&& 引用限定符不同、参数类型看似相同实则隐式转换(如
intvssize_t)都会导致 hiding - 父类函数没加
virtual,子类加了virtual也没用,C++ 不认——hiding 不看子类有没有virtual - 使用场景:override 用于多态分发;hiding 是名字查找(name lookup)的自然结果,常被误当作 override 用
为什么加了 override 关键字还报错?
override 是编译器检查工具,不是魔法开关。它只在“本意想 override,但实际做不到”时触发错误。
典型报错信息:'func' : function does not override any base class members 或 Clang 的 error: 'func' marked 'override' but does not override any member functions。
立即学习“C++免费学习笔记(深入)”;
- 父类函数没声明为
virtual→ 静态绑定,无法 override - 函数名拼错、大小写不对(
Func≠func)→ 名字查找失败 - 参数类型不一致:父类是
std::string_view,子类写const std::string&→ 不匹配 - 返回类型协变只允许指针/引用且指向同一继承体系,乱改返回类型也会拒掉
override
hiding 会静默干掉哪些父类重载?
子类定义任何同名函数,就会让父类所有同名函数(无论参数、const 性)在子类作用域里不可见——这是 C++ 名字查找规则决定的,和 virtual 无关。
例如父类有 void print(int) 和 void print(double),子类只写 void print(std::string),那么两个父类版本在子类对象上调用时全失效,连 obj.print(42) 都编译不过。
- 解决办法只有显式引入:
using Base::print;放在子类里,把父类所有print带进来 - 不加
using又想调父类版?只能强制转型:static_cast<base>(obj).print(42); - 这个机制跟性能无关,但影响接口可用性——尤其模板类继承时容易踩坑
虚析构函数被 hiding 有多危险?
如果父类析构是 virtual ~Base() = default;,而子类写了 ~Derived() { /*...*/ } 却没加 virtual,它仍是 virtual(继承自父类),不算 hiding;但若子类写了 void ~Derived()(语法错误)或更隐蔽的:父类析构带参数(非法)、或子类用了不同访问控制(比如父类 public,子类 private 析构),就可能破坏虚析构链。
真正危险的是:父类没虚析构,子类自己加了个非虚析构,然后用基类指针 delete 派生对象——此时不会调子类析构,资源泄漏,且编译器通常不警告。
- 判断依据:只要
delete pbase;中pbase是基类指针,指向派生对象,就必须确保基类析构是virtual - 子类析构是否加
virtual无所谓(自动继承虚性),但必须确保父类有 - 现代写法建议:基类析构一律
virtual = default;,子类也显式写~Derived() = default;,避免手写析构时遗漏
C++ 的 override 和 hiding 表面只是关键字和签名的事,实际牵扯名字查找、虚表生成、析构语义三层机制。最容易被忽略的,是 hiding 在重载场景下的“全屏蔽”特性——它不报错,却让父类多个重载同时消失,而且只在子类对象直接调用时才暴露问题。








