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

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()函数,因此不建议对对象进行类型转换,因为实际调用过程中已经不是原来的那个对象了,如果对象函数中涉及对成员的赋值或改动操作,那实际上是不会生效的。

C++浅析——虚函数的动态和静态绑定的更多相关文章

  1. C++中虚函数实现原理揭秘

            编译器到底做了什么实现的虚函数的晚绑定呢?我们来探个究竟.      编译器对每个包含虚函数的类创建一个表(称为V TA B L E).在V TA B L E中,编译器放置特定类的虚函 ...

  2. C++虚函数【Java有虚函数吗?】

    1,简单介绍 定义在基类中的函数,子类必须对其进行覆写![必须对其进行覆写?!]——Java中的接口.Abstract方法中的抽象类也有这样的要求. C++中定义: virtual void deal ...

  3. [转载]C++虚函数浅析

    原文:http://glgjing.github.io/blog/2015/01/03/c-plus-plus-xu-han-shu-qian-xi/ 感谢:单刀土豆 C++虚函数浅析 JAN 3RD ...

  4. C++中的重载,隐藏,覆盖,虚函数,多态浅析

    直到今日,才发现自己对重载的认识长时间以来都是错误的.幸亏现在得以纠正,真的是恐怖万分,雷人至极.一直以来,我认为重载可以发生在基类和派生类之间,例如: class A { public: void ...

  5. C++中虚函数的作用浅析

    虚函数联系到多态,多态联系到继承.所以本文中都是在继承层次上做文章.没了继承,什么都没得谈. 下面是对C++的虚函数这玩意儿的理解. 一, 什么是虚函数(如果不知道虚函数为何物,但有急切的想知道,那你 ...

  6. MFC浅析(7) CWnd类虚函数的调用时机、缺省实现

    CWnd类虚函数的调用时机.缺省实现 FMD(http://www.fmdstudio.net) 1. Create 2. PreCreateWindow 3. PreSubclassWindow 4 ...

  7. C++ 虚函数与纯虚函数 浅析

    [摘要] 在虚函数与纯虚函数的学习中.要求理解虚函数与纯虚函数的定义,了解虚函数与纯虚函数在实例化上的差异.掌握两者在实现上的必要性.熟悉纯虚函数在子类与孙类的函数类型.本文即针对上述问题展开阐述. ...

  8. C++:抽象基类和纯虚函数的理解

    转载地址:http://blog.csdn.net/acs713/article/details/7352440 抽象类是一种特殊的类,它是为了抽象和设计的目的为建立的,它处于继承层次结构的较上层. ...

  9. 【C++】多态性(函数重载与虚函数)

    多态性就是同一符号或名字在不同情况下具有不同解释的现象.多态性有两种表现形式: 编译时多态性:同一对象收到相同的消息却产生不同的函数调用,一般通过函数重载来实现,在编译时就实现了绑定,属于静态绑定. ...

随机推荐

  1. 用fasterjson需要注意的地方

    JSONArray.toJSONString()之后不是一个json,而是json中的一个数组 JSONObject是一个json JSON.toJSONString()不可多次使用,因为每次调用JS ...

  2. 15款帮助你实现响应式导航的 jQuery 插件

    对于我们大多数人来说,建立一个负责任的布局中最困难的方面是规划和导航的实现.由于没有真正经得起考验的通用解决方案,您可以使用的菜单设计风格将取决于正在建设的网站类型. 无论你正在建设什么类型的网站,在 ...

  3. 用js动态生成css代码

    有时候我们需要利用js来动态生成页面上style标签中的css代码,方法很直接,就是直接创建一个style元素,然后设置style元素里面的css代码,最后把它插入到head元素中.但有些兼容性问题我 ...

  4. javascript中的arguments对象

    在js中一切都是对象,连函数也是对象,函数名其实是引用函数定义对象的变量. 1.什么是arguments? 这个函数体内的arguments非常特殊,实际上是所在函数的一个内置类数组对象,可以用数组的 ...

  5. Asp.net EasyUI中的combogrid实现分页功能

    在jquery.easyUI.js 要实现分页,必须在后台接收参数时声明两个变量:page(当前第几页),rows(每页显示多少条信息),否者easyUI前台传递不了分页参数. 这两个属性的名称在ea ...

  6. jquery实现内容滚动

    HTML代码: <div class="scollNews"> <ul> <li><a href="#">1&l ...

  7. 如何在windows计划中调用备份sharepoint2010网站集的powershell脚本

    最近有个项目需要在在windows计划中使用powershell脚本备份sharepoint2010网站集,打开sharepoint的powershell执行命令管理界面的属性 查看: C:\Wind ...

  8. 内网渗透测试思路-FREEBUF

    (在拿到webshell的时候,想办法获取系统信息拿到系统权限) 一.通过常规web渗透,已经拿到webshell.那么接下来作重要的就是探测系统信息,提权,针对windows想办法开启远程桌面连接, ...

  9. 【CoreData】表之间的关联

    这次是表之间怎么进行关联,要求如下: // 建立学生与班级表之间的联系 既然是表与表之间的关联,那肯定是要先创建表: // 1.创建模型文件 (相当于一个数据库里的表) // New File ——— ...

  10. Android性能优化的浅谈

    一.概要: 本文主要以Android的渲染机制.UI优化.多线程的处理.缓存处理.电量优化以及代码规范等几方面来简述Android的性能优化 二.渲染机制的优化: 大多数用户感知到的卡顿等性能问题的最 ...