94 C++对象模型探索。对象构造语义学 - 继承体系下的对象构造步骤

一.对象的构造顺序

二.虚函数的继续观察

这个结论是早都知道的 : 父类的构造函数--->子类的构造函数调用

这里使用三个类 在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

最近更新

  1. TCP协议是安全的吗?

    2024-02-02 13:18:01       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-02-02 13:18:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-02-02 13:18:01       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-02-02 13:18:01       20 阅读

热门阅读

  1. 【极简】Pytorch中的register_buffer()

    2024-02-02 13:18:01       31 阅读
  2. MySQL运维实战(5.4) MySQL元数据乱码

    2024-02-02 13:18:01       39 阅读
  3. 【springBoot】统一功能处理

    2024-02-02 13:18:01       32 阅读
  4. InDesign Server-功能介绍-IDML 文件-ID插件

    2024-02-02 13:18:01       28 阅读
  5. 第7章 网络管理

    2024-02-02 13:18:01       29 阅读
  6. ArcGIS Pro字段编号相关代码

    2024-02-02 13:18:01       32 阅读
  7. 第39章 补充定义7 仿射空间解释投影矩阵

    2024-02-02 13:18:01       28 阅读
  8. Python入门指北十七

    2024-02-02 13:18:01       32 阅读
  9. android 音频调试技巧

    2024-02-02 13:18:01       32 阅读
  10. HTML优化SEO的实用技巧

    2024-02-02 13:18:01       28 阅读
  11. undefined reference to symbol ‘pow@@GLIBC_2.0

    2024-02-02 13:18:01       32 阅读