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