从汇编的角度理解c++虚函数(二)

上一个博客写的是析构函数 从析构函数我们就可以知道了我们写c++程序的时候析构函数最好是写成虚函数,因为这样的话,释放空间的时候,会把父类 以及子类的空间都是释放了 ,然后今天我们 看的是析构函数,假如是普通的成员函数 会是怎么样 我们先来看看我们写的c++代码

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <fstream>
#include <climits>
#include <bitset>
using namespace std;
class ppx
{
    public:
    void ww()
	{
	  cout<<"i love you"<<endl;
	}
};
class xx:public ppx
{
public:
    void ww()
	{
	  cout<<"i hate you"<<endl;
	}
};
class qqx:public xx
{

    public:
      void ww()
	  {
	   cout<<"you love me"<<endl;
	  }
};
class qq:public qqx
{

public:
     void ww()
	 {
	 cout<<"you hate me"<<endl;
	 }
};
int main()
{
     ppx *x=new qq;
	 x->ww();
     delete x;
     system("pause");
	 return 0;
}

 这个运行结果 应该很好猜测 就是ppx的成员函数 就是 i love you 这个不难理解  再说之前 先看看我们的汇编语言

    46: 	 x->ww();
01371537 8B 4D F8             mov         ecx,dword ptr [x]  
0137153A E8 5F FD FF FF       call        ppx::ww (137129Eh)  

我们看到 直接call了ppx::ww 没有一丝丝的犹豫— 那么我们看看上面几个ww的情况

class xx:public ppx
    18: {
    19: public:
    20:     void ww()
    21: 	{
    22: 	  cout<<"i hate you"<<endl;
    23: 	}
    24: };
    25: class qqx:public xx
    26: {
    27: 
    28:     public:
    29:       void ww()
    30: 	  {
    31: 	   cout<<"you love me"<<endl;
    32: 	  }
    33: };
    34: class qq:public qqx
    35: {
    36: 
    37: public:
    38:      void ww()
    39: 	 {
    40: 	 cout<<"you hate me"<<endl;
    41: 	 }
    42: };

可以看出 下面几个ww都没有汇编 那么可以知道 在main里面都没有运行这个ww 那么我们可以知道 在指针类型是什么 就直接调用什么 我们可以来试试 换个指针类型  比如换成xx的指针类型 那么让我们看看运行结果是什么 果然是 i hate you 那么我们可以知道 我们 结果是运行了 i hate you 那么我们看看反汇编

    46: 	 x->ww();
00B61537 8B 4D F0             mov         ecx,dword ptr [x]  
00B6153A E8 6E FD FF FF       call        ppx::ww (0B612ADh)  

这个是调用 ww函数 call 初看 这不是和上面的一样吗? 那我看看上面ww的汇编语言 结果只有ppx 还有xx的ww汇编代码出来了 那么我们用od来单步调试 看看结果到底是怎么出来的


我们先来到call调用的位置 但是我们发现od 进入的是xx::ww 那么我们好像明白了什么  虽然父类运行了 但是是什么指针类型,就是执行那个函数 这个应该是毫无疑问的 那么当时虚函数的时候会是什么结果 我们可以重新写一下来看看 

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <fstream>
#include <climits>
#include <bitset>
using namespace std;
class ppx
{
    public:
   virtual void ww()
	{
	  cout<<"i love you"<<endl;
	}
};
class xx:public ppx
{
public:
    void ww()
	{
	  cout<<"i hate you"<<endl;
	}
};
class qqx:public xx
{

    public:
      void ww()
	  {
	   cout<<"you love me"<<endl;
	  }
};
class qq:public qqx
{

public:
     void ww()
	 {
	 cout<<"you hate me"<<endl;
	 }
};
int main()
{
     qqx *x=new qq;
	 x->ww();
     delete x;
     system("pause");
	 return 0;
}

然后我们先说结果 用ppx指针运行的结果是 you hate me 然后用xx 运行的结果也是 you hate me qqx运行的结果也是you hate me 这好像和我们想的不一样 为什么都是 you hate me 如果说qqx是因为他们是虚函数 那么为什么xx qqx也会是you hate me这个可怕的字符串 那么让我们用汇编来看看这到底是怎么回事 先看指针类型是ppx* 的时候

 46: 	 x->ww();
00E1158D 8B 45 F8             mov         eax,dword ptr [x]  
00E11590 8B 10                mov         edx,dword ptr [eax]  
00E11592 8B F4                mov         esi,esp  
00E11594 8B 4D F8             mov         ecx,dword ptr [x]  
00E11597 8B 02                mov         eax,dword ptr [edx]  
00E11599 FF D0                call        eax  
00E1159B 3B F4                cmp         esi,esp  
00E1159D E8 25 FC FF FF       call        @ILT+450(__RTC_CheckEsp) (0E111C7h)  

看到这个我还是决定用od来进行调试 然后我们可以先看看x->ww这个汇编代码 我们看到了eax的两次取地址值 从这就可以分析出来 x是有虚函数表的 (可以对照没有虚函数表的时候的汇编)然后我们就开始用od来分析 我们先看到

这个代码 大家如果有时间可以好好看看eax edx的值 这些值都很有意思 然后进入call 就会发现 运行的是


you hate me 那么我们可以知道了 他这个是直接运行了 you hate me 这串代码  那么我们知道了 原来是 在底层没有那么多的条条框框 只是直接运行了 you hate me 这个函数 而调用的时候直接就指向了 具体原因还是要看编译器的解释 还有本身语言的特性 汇编语言他只会跳到该运行的地方

关于c++的虚函数我就只能说到这里 具体是为什么  就是不怎么理解c++ 机制的 这里并不一一解释 

这里只是看底层的实现 

若哪里有错误 还请指出 orz

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值