• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

C++浅析——虚函数的动态和静态绑定

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

源自一道面试题,觉得很有意思

class CBase
{
public:
        virtual        void PrintData(int nData = 111);
};
void        CBase::PrintData(int nData /* = 111 */)
{
        printf("CBase::PrintData, nData = %d\n", nData);
}

class CDerived : public CBase
{
public:
        void PrintData(int nData = 222);
};
void        CDerived::PrintData(int nData /* = 111 */)
{
        printf("CDerived::PrintData, nData = %d\n", nData);
}

在main()中做如下调用:

 CDerived        oCDerived;
 CBase*        pCBase = (CBase*)&oCDerived;
        
 pCBase->PrintData();
(*pCBase).PrintData();
 oCDerived.PrintData();

大家先猜猜输出结果是什么?


是不是更奇怪,我们看看反汇编的代码:

14、oCDerived.PrintData();
push        0DEh
lea         ecx,[ebp-4]
call        @ILT+25(CDerived::PrintData) (0040101e)        ;直接调用CDerived::PrintData(),无虚表取址过程

15、((CBase)oCDerived).PrintData();
mov         esi,esp
push        6Fh                                                ;压入CBase::PrintData()形参
lea         ecx,[ebp-4]
push        ecx                                                ;压入oCDerived的this指针
lea         ecx,[ebp-10h]
call        @ILT+10(CBase::CBase) (0040100f)                ;调用CBase拷贝构造函数新创建了一个CBase对象
mov         dword ptr [ebp-14h],eax
mov         edx,dword ptr [ebp-14h]                        
mov         eax,dword ptr [edx]                                ;取新CBase对象的虚表
mov         ecx,dword ptr [ebp-14h]
call        dword ptr [eax]                                ;调用新CBase对象的虚表的第一个函数

15.1、CBase::CBase拷贝构造函数;
mov         dword ptr [ebp-4],ecx                        ;取this指针
mov         eax,dword ptr [ebp-4]                        
mov         dword ptr [eax],offset CBase::`vftable' (00425024)        ;虚表地址赋值,直接用的CBase虚表,而没有用CDerived的虚表
mov         eax,dword ptr [ebp-4]                        ;将this指针给eax返回

16、pCDerived->PrintData();
mov         esi,esp
push        0DEh
mov         ecx,dword ptr [ebp-8]                        ;取pCDerived
mov         edx,dword ptr [ecx]                                ;取虚表
mov         ecx,dword ptr [ebp-8]                        ;放入this指针
call        dword ptr [edx]                                ;调用虚表的第一个函数,即PrintData()

 

从上述反汇编代码中可以看出:

 

1、oCDerived.PrintData()对象调用是静态绑定的

 

2、pCDerived->PrintData()指针调用是动态绑定的,而且(*pCDerived).PrintData(),即指针实例化后的对象调用也是动态绑定的(可自行看反汇编代码)

 

3、对象的类型转换中会参数新的对象,同时会调用新对象的构造拷贝函数,但由于CBase的默认拷贝构造函数为CBase::CBase(CBase&)形式,故仍会取CBase的虚表地址给新对象的虚表初始化,故((CBase)oCDerived).PrintData();实际上是调用了一个全新的CBase对象的PrintData()函数,因此不建议对对象进行类型转换,因为实际调用过程中已经不是原来的那个对象了,如果对象函数中涉及对成员的赋值或改动操作,那实际上是不会生效的。

 


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
C#上传文件小函数发布时间:2022-07-13
下一篇:
零基础如何快速精通C语言?要注意什么?发布时间:2022-07-13
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap