- UID
- 2198
注册时间2005-6-29
阅读权限255
最后登录1970-1-1
副坛主
该用户从未签到
|
构造:
B() ==> 父类构造 ==> 初始化列表(俺类内定义)==> 为虚表赋值 ==> 执行代码区
析构:
~B() ==> 先赋虚表 ==> 然后执行代码 ==> 析构(类)成员(对象) ==> 析构父类
============================
构造函数()
{
父类构造
初始化列表//const、引用、构造成员对象
为虚表赋值
执行代码
};
析构函数()
{
先赋虚表
执行代码
析构成员对象
析构父类
};
============================
new()
{
}
delete()
{
}
============================
new[]()
{
}
delete[]()
{
}
============================
虚继承
9: D thed;
004010E8 push 1
004010EA lea ecx,[ebp-14h]
004010ED call @ILT+30(D::D) (00401023)
10: return 0;
004010F2 mov dword ptr [ebp-18h],0
004010F9 lea ecx,[ebp-14h]
004010FC call @ILT+35(D::`vbase destructor') (00401028)
00401101 mov eax,dword ptr [ebp-18h]
11: }
//
EBP-14H 1
EBP-10H this
EBP-04H 0
EBP+8 0
D::`vbtable' (00425060)
D::`vbtable' (00425054)
0
xx (A::A) (0040102d)
xx
0040167F mov dword ptr [ebp-10h],ecx
00401682 mov dword ptr [ebp-14h],0
00401689 cmp dword ptr [ebp+8],0
0040168D je D::D+6Dh (004016bd)
// 先赋了两张虚表值
0040168F mov eax,dword ptr [ebp-10h]
00401692 mov dword ptr [eax],offset D::`vbtable' (00425060)
00401698 mov ecx,dword ptr [ebp-10h]
0040169B mov dword ptr [ecx+4],offset D::`vbtable' (00425054)
//
00425060
00425054
CCCCCCCC
CCCCCCCC ==> 0042502c
CCCCCCCC 00382948
004016A2 mov ecx,dword ptr [ebp-10h]
004016A5 add ecx,0Ch
004016A8 call @ILT+40(A::A) (0040102d) // 先构造祖父
004016AD mov edx,dword ptr [ebp-14h] // 0
004016B0 or edx,1
004016B3 mov dword ptr [ebp-14h],edx // 0
004016B6 mov dword ptr [ebp-4],0
004016BD push 0
004016BF mov ecx,dword ptr [ebp-10h]
004016C2 call @ILT+25(B::B) (0040101e) // B类构造时传入的就是 this 指针
004016C7 mov dword ptr [ebp-4],1
004016CE push 0
004016D0 mov ecx,dword ptr [ebp-10h]
004016D3 add ecx,4
004016D6 call @ILT+10(CC::CC) (0040100f) // CC类构造时传入的是 (this + 4) 指针
004016DB mov eax,dword ptr [ebp-10h]
004016DE mov ecx,dword ptr [eax]
004016E0 mov edx,dword ptr [ecx+4]
004016E3 mov eax,dword ptr [ebp-10h]
004016E6 mov dword ptr [eax+edx],offset D::`vftable' (00425050) // 赋值自己的虚表
14: m_d = 30;
004016ED mov ecx,dword ptr [ebp-10h]
004016F0 mov dword ptr [ecx+8],1Eh
15: }
// 从流程上看 虚继承就是多了一个先赋值两个父类虚表的流程
//
00425060
00425054
CCCCCCCC B CC D
0042502c ==> 00425030 ==> 00425040 ==> 00425050
00382948
B::B() 的构造
0040130A mov dword ptr [ebp-4],ecx
0040130D mov dword ptr [ebp-8],0
00401314 cmp dword ptr [ebp+8],0 // 压入的数据为0
00401318 je B::B+47h (00401337)
//------------------------------------------
0040131A mov eax,dword ptr [ebp-4]
0040131D mov dword ptr [eax],offset B::`vbtable' (00425034) // 修改 D对象 第一项数据
00401323 mov ecx,dword ptr [ebp-4]
00401326 add ecx,4 // 为什么要加4呢 他为什么要做两张虚表呢 ?
00401329 call @ILT+40(A::A) (0040102d) // A 类的构造为 (this+4)的地址
0040132E mov ecx,dword ptr [ebp-8] // 0
00401331 or ecx,1
00401334 mov dword ptr [ebp-8],ecx // 1
00401337 mov edx,dword ptr [ebp-4]
------------------------------------------//
0040133A mov eax,dword ptr [edx] // 取虚表第一项
0040133C mov ecx,dword ptr [eax+4] // 虚表之后的一个数据
0040133F mov edx,dword ptr [ebp-4]
00401342 mov dword ptr [edx+ecx],offset B::`vftable' (00425030) // 再次赋值赋值派生类的虚表
14:
15: }
==> 00425060
//
00000000
0C000000
00425060
00425054
CCCCCCCC
0042502c ==> 00425030
00382948
CC::CC() 的构造
004014BA mov dword ptr [ebp-4],ecx
004014BD mov dword ptr [ebp-8],0
004014C4 cmp dword ptr [ebp+8],0
004014C8 je CC::CC+47h (004014e7)
//------------------------------------------
004014CA mov eax,dword ptr [ebp-4]
004014CD mov dword ptr [eax],offset CC::`vbtable' (00425044) // 修改 D对象 的第二项
004014D3 mov ecx,dword ptr [ebp-4]
004014D6 add ecx,4
004014D9 call @ILT+40(A::A) (0040102d)
004014DE mov ecx,dword ptr [ebp-8] // 1
004014E1 or ecx,1
004014E4 mov dword ptr [ebp-8],ecx
------------------------------------------//
004014E7 mov edx,dword ptr [ebp-4]
004014EA mov eax,dword ptr [edx]
004014EC mov ecx,dword ptr [eax+4]
004014EF mov edx,dword ptr [ebp-4]
004014F2 mov dword ptr [edx+ecx],offset CC::`vftable' (00425040) // 再次赋值赋值派生类的虚表
14:
// 00425054
==>
00000000
08000000
00425060
00425054
CCCCCCCC B CC
0042502c ==> 00425030 ==> 00425040
00382948
//
00425054 00 00 00 00 .... -->
00425058 08 00 00 00 ....
0042505C 00 00 00 00 ....
00425060 00 00 00 00 .... -->
00425064 0C 00 00 00 ....
00425068 00 00 00 00
// 注意哦 B类构造 和 CC类构造 的一个数据
00425034
00425044
// 这里不仅保存了虚表地址 还保留了父类的偏移地址
00425030 0A 10 40 00 ..@. ----> B 类虚表地址
00425034 00 00 00 00 ....
00425038 04 00 00 00 .... //
0042503C 00 00 00 00 ....
00425040 32 10 40 00 2.@. ----> CC 类虚表地址
00425044 00 00 00 00 ....
00425048 04 00 00 00 .... //
0042504C 00 00 00 00 ....
00425050 64 10 40 00 .... ----> D 类虚表地址 (虚表后是一个 DWORD[3] 的结构体哦)
// 果然是虚表第一项 00401064
00425054 00 00 00 00 .... // 虚表第二数值 CC 类构造时 相对于 A 类的偏移地址
00425058 08 00 00 00 ....
0042505C 00 00 00 00 ....
00425060 00 00 00 00 .... ---->
00425064 0C 00 00 00 .... 虚表第一数值 B 类构造时 相对于 A 类的偏移地址
00425068 00 00 00 00 ....
MOV EDX,[EBP-4]
MOV EAX,[EAX+4]
MOV ECX,[EAX+4] // 这里如果是自己构造则为 4
MOV EDX,[EBP-4]
[EDX + ECX]
==> 构造完成后 都要修改父类的虚表地址
D 类的虚继承方案
1. 先赋值两张数据
2. 然后构造 祖父类
3. 然后再构造 B 和 CC 类时压入参数 0
B 和 CC 中的构造判断 参数 = 0
则跳过 A 类的构造
自己赋值虚表后,然后修改派生类的虚表
4. 赋值自己的虚表
// ====================================================================
析构函数:
0040114A mov dword ptr [ebp-4],ecx
0040114D mov ecx,dword ptr [ebp-4]
00401150 add ecx,0Ch // 这里找到 A 类的地址传入析构函数
00401153 call @ILT+65(D::~D) (00401046)
00401158 mov ecx,dword ptr [ebp-4]
0040115B add ecx,0Ch // 这里找到 A 类的地址传入析构函数
0040115E call @ILT+55(A::~A) (0040103c)
D::~D
004017EF mov dword ptr [ebp-10h],ecx
004017F2 mov eax,dword ptr [ebp-10h]
004017F5 mov ecx,dword ptr [eax-0Ch]
004017F8 mov edx,dword ptr [ecx+4]
004017FB mov eax,dword ptr [ebp-10h]
004017FE mov dword ptr [eax+edx-0Ch],offset D::`vftable' (00425050)
00401806 mov dword ptr [ebp-4],0
19:
20: }
0040180D mov ecx,dword ptr [ebp-10h]
00401810 sub ecx,0Ch
00401813 test ecx,ecx
00401815 je D::~D+62h (00401822)
00401817 mov edx,dword ptr [ebp-10h]
0040181A sub edx,8
0040181D mov dword ptr [ebp-14h],edx
00401820 jmp D::~D+69h (00401829)
00401822 mov dword ptr [ebp-14h],0
00401829 mov ecx,dword ptr [ebp-14h]
0040182C add ecx,4
0040182F call @ILT+80(CC::~CC) (00401055) // 反顺序先析构 CC
00401834 mov dword ptr [ebp-4],0FFFFFFFFh
0040183B mov ecx,dword ptr [ebp-10h]
0040183E sub ecx,8
00401841 call @ILT+60(B::~B) (00401041) // // 反顺序先析构 B
00401846 mov ecx,dword ptr [ebp-0Ch]
D::~D `vbase destructor' (调用自己的虚表第一项)
析构自身,自身的析构去调用其继承的父类 ( CC 和 B )
而所继承的父类 他们虚继承了 A 类,所以在 CC 和 B 类的析构中不对A类做任何处理
然后再去析构 A 类 |
|