Nisy 发表于 2010-1-30 02:53:24

虚析构简单分析(关于菱形结构)

构造:
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 类

MeowCat 发表于 2010-1-31 22:52:21

/:002 /:002   这还叫简单分析啊

PYG_DEBUG_ 发表于 2010-2-6 00:07:23

页: [1]
查看完整版本: 虚析构简单分析(关于菱形结构)