C++类重写疑问:为何添加const后未调用Derived类虚函数
核心问题出在模板参数与const结合时的类型差异,以及C++虚函数覆盖的签名匹配规则:
1. 基类的参数类型拆解
当实例化A<int*>时,基类中的virtual void some_function(const T a),这里的const T等价于const (int*),也就是**int* const a**——这个const修饰的是指针本身,意思是指针变量a的指向不可修改,但指针指向的int值可以修改。
2. 派生类的参数类型错误匹配
你最初在派生类中写的virtual void some_function(const int* a),这里的const修饰的是int,实际类型是**const int* a**——意思是指针a的指向可以修改,但指针指向的int值不可修改。
这两个参数类型完全不同,因此派生类的这个函数并没有**覆盖(override)**基类的虚函数,而是定义了一个新的独立虚函数。当用基类指针A<int*>* p调用some_function时,编译器匹配的是基类的虚函数版本,所以输出Base。
3. 移除const后成功覆盖的原因
当去掉派生类参数的const,参数类型变为int* a,此时和基类的int* const a属于等价的函数签名——因为函数参数中的顶层const(修饰参数本身的const)会被编译器忽略,编译器认为这两个函数的签名一致。因此派生类的函数成功覆盖了基类的虚函数,基类指针调用时触发多态,执行派生类的版本,输出Derived。
避坑建议
在派生类中重写虚函数时,一定要加上override关键字,比如:
class Derived : public A<int*> { public: // 加上override后,编译器会检查是否真的覆盖了基类虚函数,不匹配会直接报错 virtual void some_function(const int* a) override; };
这样如果参数类型不匹配,编译器会直接提示错误,避免你误以为函数被覆盖而出现预期外的行为。
内容的提问来源于stack exchange,提问作者ALPHA

