分析一个在基类的构造函数中调用虚函数的问题。
#include <iostream>
using namespace std;
class A {
public:
virtual void init() {
cout<<"A"<<endl;
}
A() {
test();
}
};
class B: public A {
public:
virtual void init() {
cout<<"B"<<endl;
}
};
int main() {
B* b = new B();
b->init();
return 0;
}
结果会输出
AB
分析背后的原因。
A有一个虚函数,所以会增加一个__vfptr的成员,虚指针。该成员在A的构造函数中初始化,伪代码为
A::A() {
this->__vfptr = A::vfptr;
this->__vfptr[0](); // this->init(); 调用第一个虚函数
}
B的构造函数伪代码如下:
B::B() {
this->A::A();
this->__vfptr = B::vfptr;
}
所以在调用B的构造函数的时候,会调用A的构造函数, A的构造函数会调用类的第一个虚函数init。
虚函数是通过虚指针加函数下标调用的,调用init即为调用__vfptr[0]()。
因为在A的构造函数中,__vfptr会先初始化为A::vfptr, 所以会先调用A::init。
所以先输出A。
第二次b->init()。转化一下,同样是
b->__vfptr[0](); //b->init();
因为调用完B的构造函数后,__vfptr被B::vfptr初始化,所以后面调用init,是B::init。
所以输出B。
意识到__vfptr的存在和初始化,可以了解虚函数调用的本质,看透背后的原理。
网友评论