在C++中,孙子类可以重写爷爷类的虚函数,并且仍然保持多态性。即使父亲类没有显式重写该虚函数,孙子类的重写仍然有效,虚函数表(vtable)的继承链不会被中断。
核心概念说明:
- 虚函数继承:虚函数特性会跨代传递
- 多态保持:通过基类指针/引用调用虚函数时,会根据实际对象类型动态绑定
- 隐式继承:父亲类虽然不显式重写,但仍继承爷爷类的虚函数声明
简单示例代码:
#include <iostream>
using namespace std;
class Grandpa {
public:
virtual void DoSomething() {
cout << "爷爷的函数" << endl;
}
};
class Father : public Grandpa {
// 不重写虚函数,但隐式继承爷爷的虚函数
};
class Grandson : public Father {
public:
void DoSomething() override { // ✅ 孙子类重写爷爷的虚函数
cout << "孙子的实现" << endl;
}
};
int main() {
Grandpa* ptr = new Grandson(); // 基类指针指向孙子对象
ptr->DoSomething(); // 输出:孙子的实现 ➡️ 多态生效!
delete ptr;
return 0;
}
关键解析:
-
函数调用过程:
- 当通过
Grandpa*
调用DoSomething()
时 - 编译器检查
Grandpa::DoSomething
是虚函数 - 查询实际对象(Grandson) 的虚函数表
- 定位到
Grandson::DoSomething
并调用
- 当通过
-
虚函数表继承链:
爷爷类的vtable: [ Grandpa::DoSomething ]
父亲类的vtable: [ Grandpa::DoSomething ] // 自动继承
孙子类的vtable: [ Grandson::DoSomething ] // 覆盖函数指针
- override关键字:在C++11+中明确表示重写关系(非必须但推荐)
多态生效的条件:
- 继承关系必须存在(爷爷←父亲←孙子)
- 必须通过基类的指针或引用调用
- 函数必须保持虚函数属性(自动跨代传递)
- 函数签名完全相同(函数名、参数、const限定)
⚠️ 注意:即使父亲类不重写虚函数,也可以在父亲类和孙子类之间直接建立多态(
Father* f = new Grandson(); f->DoSomething();
同样输出"孙子的实现")