一、问题探讨
大家是否有在子类或基类构造函数中调用虚函数的情况呢?语法是否支持?执行情况如何呢?为什么呢?
二、问题验证
这个问题的最好答案是亲自写个demo调试下看看结果如何,下面是demo代码(vs2019):
1 class Base { 2 public: 3 Base() { 4 cout << "Base::ctor "; 5 Func(); 6 } 7 virtual void Func() { 8 cout << "Base::Func "; 9 } 10 }; 11 12 class D : public Base { 13 public: 14 D() { 15 cout << "D::ctor "; 16 Func(); 17 } 18 19 void Func() override { 20 cout << "D::Func "; 21 } 22 };
客户端调用代码
1 int main() 2 { 3 auto d = std::make_shared<D>(); 4 5 return 0; 6 }
输出结构如下:
子类构造函数调用虚函数调用的是子类重写的,基类构造函数调用的是基类的虚函数。可以回答问题中的前两个疑问,语法支持,执行情况如上;但是并没有调用子类重新的虚函数呢?继续分析。
三、原因分析
回答这个问题,我们可以直接使用VS2019的调试器即可。我们需要在基类和子类的构造函数中分别打上断点,如下:
我们知道构造子类前需要先构造基类,在进入基类构造函数实现体前,虚函数表是空的:
进入构造体后,虚表指向基类的虚函数地址:
进入子类构造体前,虚表还是基类的虚函数地址:
进入子类构造体后,虚表地址替换为子类的:
通过上面详细的调试步骤和对象内存虚表信息即可知道为什么了吧!