这个结论是早都知道的 : 父类的构造函数--->子类的构造函数调用
这里使用三个类 在vs2017中观察,构造顺序,这里主要是学习方法,有了方法后,在遇见后面复杂的case下可以自己debug
//通过反汇编观察
class Teacher28grandpa {
public:
Teacher28grandpa() {
cout << "Teacher28grandpa 构造方法被调用" << endl;
}
~Teacher28grandpa() {
cout << "Teacher28grandpa xigou 方法被调用" << endl;
}
virtual void virfunc() {
cout << "Teacher28grandpa virfunc 方法被调用" << endl;
}
};
class Teacher28father :public Teacher28grandpa {
public:
Teacher28father() {
cout << "Teacher28father 构造方法被调用" << endl;
}
~Teacher28father() {
cout << "Teacher28father xigou 方法被调用" << endl;
}
virtual void virfunc() {
cout << "Teacher28father virfunc 方法被调用" << endl;
}
};
class Teacher28 :public Teacher28father {
public:
//这里还使用了 初始化成员列表,顺便观察一下 mage的值是什么时候
Teacher28(int age):mage(age) {
cout << "Teacher28 构造方法被调用" << endl;
}
~Teacher28() {
cout << "Teacher28 xigou 方法被调用" << endl;
}
//这里有虚函数,目的是观察,虚函数在构造方法中是如何构造的。
virtual void virfunc() {
cout << "Teacher28 virfunc 方法被调用" << endl;
}
int mage;
};
void main() {
Teacher28grandpa *ptea = new Teacher28(888);
ptea->virfunc();
}
结果:
Teacher28grandpa *ptea = new Teacher28(888);
00DFFD82 call Teacher28::Teacher28 (0DF1429h) //内部调用
00DF68FF call Teacher28father::Teacher28father (0DF135Ch) //内部调用
00DF69FF call Teacher28grandpa::Teacher28grandpa (0DF1735h) //内部调用
00DF6AD0 mov dword ptr [eax],offset Teacher28grandpa::`vftable' (0E08E64h) //虚函数指针的赋值
cout << "Teacher28grandpa 构造方法被调用" << endl;
00DF6A0E mov dword ptr [eax],offset Teacher28father::`vftable' (0E08EECh) //虚函数指针的赋值
cout << "Teacher28father 构造方法被调用" << endl;
00DF690E mov dword ptr [eax],offset Teacher28::`vftable' (0E08F74h) //虚函数指针的赋值
00DF6917 mov ecx,dword ptr [age] //这是初始化列表赋值的时机
cout << "Teacher28 构造方法被调用" << endl;
结论:
Teacher28grandpa *ptea = new Teacher28(888);
00DFFD82 call Teacher28::Teacher28 (0DF1429h) //内部调用
00DF68FF call Teacher28father::Teacher28father (0DF135Ch) //内部调用
00DF69FF call Teacher28grandpa::Teacher28grandpa (0DF1735h) //内部调用
00DF6AD0 mov dword ptr [eax],offset Teacher28grandpa::`vftable' (0E08E64h) //虚函数指针的赋值 1
cout << "Teacher28grandpa 构造方法被调用" << endl; 2
00DF6A0E mov dword ptr [eax],offset Teacher28father::`vftable' (0E08EECh) //虚函数指针的赋值 3
cout << "Teacher28father 构造方法被调用" << endl; 4
00DF690E mov dword ptr [eax],offset Teacher28::`vftable' (0E08F74h) //虚函数指针的赋值 5
00DF6917 mov ecx,dword ptr [age] //这是初始化列表赋值的时机 6
cout << "Teacher28 构造方法被调用" << endl; 7
结论:
在构造函数中调用虚函数,不会走虚函数指针。
class Teacher28 :public Teacher28father {
public:
//这里还使用了 初始化成员列表,顺便观察一下 mage的值是什么时候
Teacher28(int age):mage(age) {
cout << "Teacher28 构造方法被调用 start" << endl;
virfunc();
cout << "Teacher28 构造方法被调用 end" << endl;
}
~Teacher28() {
cout << "Teacher28 xigou 方法被调用" << endl;
}
//这里有虚函数,目的是观察,虚函数在构造方法中是如何构造的。
virtual void virfunc() {
cout << "Teacher28 virfunc 方法被调用" << endl;
}
int mage;
};
但是从debug来看,这时候虚函数指针已经有值了,但是编译器还是没有走 虚函数指针查找。
这可以理解为:当构造函数还没有完全好的时候,不让走。
debug 构造方法中的 virfunc() 方法,如下:
virfunc();
00546946 mov ecx,dword ptr [this]
00546949 call Teacher28::virfunc (05411A9h)
cout << "Teacher28 构造方法被调用 end" << endl;
奇怪的现象:构造函数中调用虚函数1,然后再虚函数1中调用虚函数2
注意:这里会有不同,调用虚函数1是不会走虚函数指针,但是虚函数2会走虚函数指针。
这里使用三个类 在vs2017中观察,构造顺序,这里主要是学习方法,有了方法后,在遇见后面复杂的case下可以自己debug