思考virtual析构

Author:zfive5(zhaozidong)

Email:zfive5@yahoo.com.cn

最近同住的朋友忙着找工作,他C++的问题看了一堆,我也受其影响复习了一些C++知识, virtual析构听他说“点播率还挺高的”,所以拿来仔细研究,求个深解!

 

首先,定义3个类,注意了析构函数的virtual 说明

class ZF5_1

{

public:

         ZF5_1()

         {      

         }

 

         virtual ~ZF5_1()

         {

                  printf("Hello ZF5_1/r/n");

         }

};

 

class ZF5_2:public ZF5_1

{

public:

         ZF5_2()

         {

         };

         virtual ~ZF5_2()

         {

                  printf("Hello ZF5_2/r/n");

         };

};

class ZF5_3:public ZF5_2

{

public:

         ZF5_3()

         {

         };

         virtual ~ZF5_3()

         {

                  printf("Hello ZF5_3/r/n");

         };

};

 

然后执行代码:

         ZF5_1 *p5=new ZF5_3;

         delete p5;

 

 

1.如果都有virtual

输出:

Hello ZF5_3

Hello ZF5_2

Hello ZF5_1

 

 

2.如果都去掉virtual

输出:

Hello ZF5_1

 

 

3.如果只去掉ZF5_2virtual

输出:

Hello ZF5_3

Hello ZF5_2

Hello ZF5_1

 

 

第一种情况

虽然delete是基类指针,但由于有virtual析构声明,所以delete调用的派生类的析构(派生类用自己的析构函数指针重写虚函数表),然后派生类析构完成后再调用直接基类析构(C++就是这样规定的,编译器隐含这个过程,通过看汇编代码,一切机理ok),这样一级级的调用,就出现了第一种输出!

 

第二种情况

由于没有virtual修饰,所以delete调用是默认的ZF5_1析构,出现第二种输出就理所当然了。

 

第三种情况

由于ZF5_1virtual修饰,所以以后所有它的派生类用自己的析构函数指针重写虚函数表里的对应的位置,以至出现与第一种情况相同的结果!

     

有一种情况没有表达,就是如果定义如下:

virtual   ZF5_1

        ZF5_2

        ZF5_3

        ZF5_4

       

ZF5_2 *p1=new Z5_4;

delete p1;

 

输出:

Hello ZF5_4

Hello ZF5_3

Hello ZF5_2

Hello ZF5_1

 

这种情况在VC6下,只要有基类virtual声名,以后的派生类都自动加上virtual,不知道gcccb是怎样处理这种情况的!有机会验证一下,对了很有可能是C++标准规定,看来还得先去翻翻C++ Primer了。

 

 

ZF5_3析构完成后默认调用ZF5_2析构汇编代码:(VC6环境下)

52:        ~ZF5_3()

53:       {

004013E0   push        ebp

004013E1   mov         ebp,esp

004013E3   sub         esp,44h

004013E6   push        ebx

004013E7   push        esi

004013E8   push        edi

004013E9   push        ecx

004013EA   lea         edi,[ebp-44h]

004013ED   mov         ecx,11h

004013F2   mov         eax,0CCCCCCCCh

004013F7   rep stos    dword ptr [edi]

004013F9   pop         ecx

004013FA   mov         dword ptr [ebp-4],ecx

004013FD   mov         eax,dword ptr [ebp-4]

00401400   mov         dword ptr [eax],offset ZF5_3::`vftable' (00423044)

54:           printf("Hello ZF5_3/r/n");

00401406   push        offset string "Hello ZF5_3/r/n" (00424050)

0040140B   call        printf (00401e40)

00401410   add         esp,4

55:       };

00401413   mov         ecx,dword ptr [ebp-4]

00401416   call        @ILT+145(ZF5_2::~ZF5_2) (00401096)

0040141B   pop         edi

0040141C   pop         esi

0040141D   pop         ebx

0040141E   add         esp,44h

00401421   cmp         ebp,esp

00401423   call        __chkesp (00401e00)

00401428   mov         esp,ebp

0040142A   pop         ebp

0040142B   ret

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值