推荐答案
在C++中,虚函数表(vtable)和虚指针(vptr)是实现多态性的关键机制。
虚函数表(vtable)
- 定义:虚函数表是一个存储类中虚函数地址的数组。每个包含虚函数的类都有一个对应的虚函数表。
- 作用:当调用一个虚函数时,编译器通过虚函数表来查找并调用正确的函数实现。
- 存储位置:虚函数表通常存储在只读数据段(.rodata)中。
虚指针(vptr)
- 定义:虚指针是一个指向虚函数表的指针。每个包含虚函数的类的对象都有一个虚指针。
- 作用:虚指针用于在运行时确定调用哪个虚函数。
- 存储位置:虚指针通常存储在对象的内存布局的开头部分。
示例代码
// www.javascriptcn.com code example
class Base {
public:
virtual void func1() { std::cout << "Base::func1" << std::endl; }
virtual void func2() { std::cout << "Base::func2" << std::endl; }
};
class Derived : public Base {
public:
void func1() override { std::cout << "Derived::func1" << std::endl; }
void func2() override { std::cout << "Derived::func2" << std::endl; }
};
int main() {
Base* b = new Derived();
b->func1(); // 输出: Derived::func1
b->func2(); // 输出: Derived::func2
delete b;
return 0;
}本题详细解读
虚函数表的工作原理
- 虚函数表的创建:当一个类包含虚函数时,编译器会为该类生成一个虚函数表。这个表包含了该类所有虚函数的地址。
- 虚指针的初始化:当创建该类的对象时,对象的虚指针会被初始化为指向该类的虚函数表。
- 函数调用:当通过基类指针或引用调用虚函数时,编译器会通过虚指针找到虚函数表,并从表中查找对应的函数地址进行调用。
虚指针的作用
- 动态绑定:虚指针使得C++能够在运行时确定调用哪个函数,从而实现动态绑定(即多态性)。
- 对象内存布局:虚指针通常位于对象内存布局的开头,这使得编译器能够快速访问虚函数表。
虚函数表的存储
- 只读数据段:虚函数表通常存储在只读数据段中,以防止程序在运行时修改虚函数表的内容。
- 每个类一个表:每个包含虚函数的类都有自己的虚函数表,派生类会继承基类的虚函数表,并在需要时进行扩展或覆盖。
示例代码解析
- Base类:
Base类有两个虚函数func1和func2,编译器会为Base类生成一个虚函数表,表中包含这两个函数的地址。 - Derived类:
Derived类继承了Base类,并重写了func1和func2。Derived类的虚函数表会覆盖Base类中对应的函数地址。 - 多态调用:在
main函数中,通过Base类指针调用func1和func2时,实际调用的是Derived类中的实现,这是因为虚指针指向了Derived类的虚函数表。
通过虚函数表和虚指针,C++实现了运行时多态性,使得程序能够在运行时根据对象的实际类型调用正确的函数。