1.类初始化
通过类对象调用函数时,this指针会作为第一个参数
class MySharePtr {public:MySharePtr(int val) : a(val) {// a = val; // 不使用初始化列表的方式}int a = 10;
};// 使用初始化列表的方式, 直接使用传入的参数进行构造
MySharePtr::MySharePtr(int) [base object constructor]:push rbpmov rbp, rspmov QWORD PTR [rbp-8], rdimov DWORD PTR [rbp-12], esimov rax, QWORD PTR [rbp-8]mov edx, DWORD PTR [rbp-12]mov DWORD PTR [rax], edxnoppop rbpret// 不使用初始化列表的方式, 在有默认值的情况下,明显是先按照默认值赋值后,再使用传入的参数进行构造
MySharePtr::MySharePtr(int) [base object constructor]:push rbpmov rbp, rspmov QWORD PTR [rbp-8], rdimov DWORD PTR [rbp-12], esimov rax, QWORD PTR [rbp-8]mov DWORD PTR [rax], 10mov rax, QWORD PTR [rbp-8]mov edx, DWORD PTR [rbp-12]mov DWORD PTR [rax], edxnoppop rbpret
因此对于常量成员或引用类型成员,必须在初始化列表中进行初始化,因为它们无法在构造函数体内赋值。
动态内存调用,因为事先知道类的大小,因此首先将该类大小作为第一个参数,调用new函数申请空间,再调用相应构造函数。
2.多重继承下的虚函数
- 之前,看其他博客上,有很多人说多重继承下虚函数表指针是依次放在类存储空间头部的。
但,今天在看gcc13.2编译后的汇编代码时,发现虚函数表指针在存储的布局如下所示
vptr base class1
base class1 datamember
vptr base class2
base class2 datamembervtable for Soccerr:.quad 0.quad typeinfo for Soccerr.quad Soccerr::printId().quad Soccerr::printId3().quad Soccerr::printId4().quad -16.quad typeinfo for Soccerr.quad PlayerSP::printIdSP()
这种方式在类初始化时比较简单,因为已经知道基类大小,只需要初始化基类1,偏移基类1大小,初始化基类2即可。
2. 上述的.quad -16
表示的是,将Soccerr
类转换为PlayerSP
基类的偏移量。