面试题答案
一键面试虚函数表与对象内存布局
- 虚函数表:当类中存在虚函数时,编译器会为该类创建一个虚函数表(Virtual Table,简称 vtable)。虚函数表是一个存储虚函数地址的数组,每个虚函数在表中都有一个对应的条目,存放该虚函数的实际地址。
- 对象内存布局:每个包含虚函数的对象在内存中首先会有一个指向虚函数表的指针(vptr),这个指针通常位于对象内存布局的起始位置。之后才是对象的其他成员变量。例如,假设有如下类定义:
class Base {
public:
virtual void virtualFunction() {}
int data;
};
每个 Base
对象在内存中的布局大致为:[vptr | data]
。vptr
指向 Base
类的虚函数表,虚函数表中存放着 virtualFunction
的地址。
3. 成员函数区分不同对象成员数据:成员函数通过 this
指针来区分不同对象的成员数据。this
指针是成员函数的隐含参数,指向调用该成员函数的对象。当一个对象调用成员函数时,this
指针会被作为参数传递给成员函数,这样成员函数就可以根据 this
指针访问到该对象的成员数据。
动态类型转换时的协同工作机制
- 向上转型:当进行向上转型(例如从派生类对象转换为基类对象)时,由于派生类对象的内存布局中开头部分包含基类对象的布局,因此只需要将派生类对象的指针转换为基类对象指针即可。虚函数机制不受影响,因为派生类对象的
vptr
指向的虚函数表包含了基类虚函数表的内容(覆盖或继承),通过vptr
依然可以正确调用到合适的虚函数,并且虚函数内部通过this
指针可以正确访问到对应对象(此时是派生类对象中基类部分)的成员数据。 - 向下转型:当进行向下转型(例如从基类对象指针转换为派生类对象指针)时,通常使用
dynamic_cast
。dynamic_cast
会利用运行时类型信息(RTTI)来判断转型是否合法。如果转型成功,得到的派生类对象指针就可以正确访问派生类特有的成员数据。在调用虚函数时,虚函数表机制依然起作用,由于vptr
指向的虚函数表是派生类的虚函数表,所以会调用到派生类中合适的虚函数实现,并且通过this
指针可以访问到派生类对象的所有成员数据。
在 C++ 中,虚函数表、对象内存布局以及 this
指针在处理动态类型转换时协同工作,确保成员函数能够正确访问对应对象的成员数据,维持面向对象编程中多态性和数据访问的正确性。