面试题答案
一键面试1. C++虚函数表的结构和作用
结构
- 虚函数表是一个存储类虚函数地址的数组。每个包含虚函数的类都有一个对应的虚函数表。
- 当类对象被创建时,编译器会在对象内存布局的起始位置插入一个指向该类虚函数表的指针(vptr)。
- 虚函数表中的每个条目都是一个虚函数的地址。对于从基类继承来的虚函数,其在虚函数表中的位置与基类虚函数表中该函数的位置相同。
作用
- 实现多态性:虚函数表使得C++能够在运行时根据对象的实际类型来调用合适的虚函数,从而实现动态绑定。
- 解耦函数调用和实际函数实现:通过虚函数表,函数调用不再在编译时静态确定,而是在运行时根据对象的动态类型确定。
2. 虚函数表如何支持动态联编
- 编译阶段:编译器在编译时为每个包含虚函数的类生成虚函数表,并为每个对象添加vptr。当调用虚函数时,编译器生成代码通过vptr找到虚函数表,然后根据虚函数在表中的索引来调用函数。
- 运行阶段:在运行时,对象的实际类型决定了vptr所指向的虚函数表。因此,即使通过基类指针或引用进行函数调用,也能根据对象的实际类型找到正确的虚函数版本,实现动态联编。
3. 多重继承情况下虚函数表的变化及对动态联编的影响
虚函数表变化
- 在多重继承中,一个派生类从多个基类继承。此时,派生类会有多个虚函数表,每个基类对应一个虚函数表。
- 派生类的vptr会指向第一个基类的虚函数表。对于其他基类的虚函数表,通过偏移量来访问。
对动态联编的影响
- 动态联编仍然有效,但由于存在多个虚函数表,编译器在通过指针或引用调用虚函数时,需要根据对象类型确定使用哪个虚函数表。这增加了查找虚函数地址的复杂性。
- 例如,当通过基类指针调用虚函数时,编译器需要根据指针类型确定对应的虚函数表,然后在表中查找函数地址。
4. 虚继承情况下虚函数表的变化及对动态联编的影响
虚函数表变化
- 在虚继承中,为了避免菱形继承导致的重复基类数据,虚基类的数据在派生类对象内存布局中有特殊的位置。
- 虚函数表中除了包含虚函数地址,还会包含一些额外的信息,如指向虚基类子对象的偏移量。
- 虚继承下,派生类对象的vptr指向的虚函数表结构更复杂,以处理虚基类的情况。
对动态联编的影响
- 动态联编依然可以正常工作,但由于虚函数表结构的变化,在运行时查找虚函数地址和虚基类子对象偏移量时会增加复杂性。编译器需要根据虚函数表中的额外信息来正确定位虚函数和虚基类子对象。