虚函数有两种调用方式:

  • 方案1,直接使用函数地址调用。
  • 方案2,通过对象的虚函数表指针找到虚函数表,从而得到函数地址,完成调用。

应用场景主要有如下三种情况:

  1. 当对象直接调用时,采用方案 1 调用虚函数。
  2. 当对象的指针或者引用调用时,采用方案 2 调用虚函数。
  3. 类成员函数中调用虚函数。

(1)若是直接调用,则走方案 2 路线。

(2)若是使用 类名::虚函数,则走方案 1 路线。

栗子:

class CBase
{
public:virtual void func() { std::cout << "CBase::func()" << std::endl; }
};class CA : public CBase
{
public:void func() { std::cout << "CA::func()" << std::endl; }void func_1() { CBase::func(); }void func_2() { func(); }
};

(1)当执行如下代码时,

CA A;
A.func();
CBase Base;
Base.func();

结果为

CA::func()
CBase::func()

转成汇编,

005D29F6  call        CA::func (05D1325h)
005D29FE  call        CBase::CBase (05D11F9h) 

可以发现,编译器采用的是直接调用的方式,与场景1相对应。

(2)当执行如下代码时,

CBase* pbase = new CA;
pbase->func();

结果为

CA::func()

转成汇编,

    27:  pbase->func();
005D2A8D  mov         eax,dword ptr [pbase]
005D2A90  mov         edx,dword ptr [eax]
005D2A92  mov         esi,esp
005D2A94  mov         ecx,dword ptr [pbase]
005D2A97  mov         eax,dword ptr [edx]
005D2A99  call        eax
005D2A9B  cmp         esi,esp
005D2A9D  call        __RTC_CheckEsp (05D12F3h)  

执行的方案是通过对象的虚函数表指针找到虚函数表,从而得到函数地址,完成调用。与场景2相对应。

(3)执行如下代码,

A.func_1();
A.func_2();

结果为

CBase::func()
CA::func()

转成汇编,

    17:      CBase::func();
0071284D  mov         ecx,dword ptr [this]
00712850  call        CBase::func (071120Dh)21:         func();
007128AD  mov         eax,dword ptr [this]
007128B0  mov         edx,dword ptr [eax]
007128B2  mov         esi,esp
007128B4  mov         ecx,dword ptr [this]
007128B7  mov         eax,dword ptr [edx]
007128B9  call        eax
007128BB  cmp         esi,esp
007128BD  call        __RTC_CheckEsp (07112F3h)  

可以发现,前者是直接调用的方式 ,后者是通过虚函数表才找到的虚函数的地址。与场景3相对应。

(SAW:Game Over!)

Cpp 对象模型探索 / 虚函数的调用方式相关推荐

  1. Cpp 对象模型探索 / 虚基类表作用

    一.结论 虚基类表的作用是帮助编译器找到该类中的虚基类中各个成员变量在内存布局中的位置. 虚基类表中的值是偏移值,即:各个虚基类的成员变量在子类中的内存布局中相对于虚函数指针的偏移值. 二.栗子 1. ...

  2. Cpp 对象模型探索 / 虚继承带虚函数的基类的子类的内存布局

    源码 class Base { public:Base() {}virtual void func() {}int bi_; };class Son:virtual public Base { pub ...

  3. Cpp 对象模型探索 / delete 运算符内部调用过程分析

    一.delete 调用过程 1.测试代码,在 delete 处打下断点. class CTest { public:CTest() {}~CTest() {} };int main() {CTest* ...

  4. Cpp 对象模型探索 / new 运算符内部调用过程分析

    一.new 调用过程 1.测试代码 class CTest { public:CTest(){} };int main() {CTest *pt1 = new CTest();delete pt1;r ...

  5. Cpp 对象模型探索 / 虚函数表和虚函数表指针的创建时机

    一.虚函数表 在编译期间创建.编译器会为每个类确定好虚函数表(vtbl)的内容. 二.虚函数表指针 虚函数表指针跟随着对象,在运行期间创建.由于在编译期间编译器为每个类创建好了 vtbl,并且编译器会 ...

  6. Cpp 对象模型探索 / 父类和子类调用构造函数和析构函数的顺序

    2018-03-19 创建人:Ruo_Xiao 邮箱:xclsoftware@163.com 一.建立对象过程 father → son 栗子: class Parent {public:Parent ...

  7. Cpp 对象模型探索 / 类静态成员函数的调用方式

    一.普通静态成员函数的调用方法 栗子: class CA { public:static void func() {} };int main() {CA A;A.func();CA::func();r ...

  8. C++对象模型8——构造函数和析构函数中对虚函数的调用、全局对象构造和析构、局部static数组的内存分配

    一.构造函数和析构函数中对虚函数的调用 仍然以https://blog.csdn.net/Master_Cui/article/details/109957302中的代码为例 base3构造函数和析构 ...

  9. Cpp 对象模型探索 / 多态的本质

    普通成员函数的调用方式是直接通过编译期间确定的函数地址来调用. 多态是通过查询对象的虚函数表来获取虚函数的地址.因为像工厂模式这样,并不能在编译期间知道基类指向的是哪个子类,也就导致了不能在编译期间获 ...

最新文章

  1. 抓项目、惠民生、促发展,雨花铿锵前进
  2. ubuntu安装qt4
  3. 牛客网(剑指offer) 第五题 用两个栈来实现一个队列
  4. java struts2国际化代码下载_【Java框架】java struts2框架中页面表示国际化的方法 - 思诚科技...
  5. 在 Windows Server 2008 R2 下用 Visual Studio 2010 编译 Chrome 与 WebKit Chromium Port
  6. 队列——数组实现和链式实现
  7. 相位编码信号 matlab,matlab 求基于相位编码的雷达回波仿真 更多交易加我QQ
  8. [kuangbin带你飞] 专题一简单搜索
  9. 网络安全-SQL注入原理、攻击及防御
  10. DNF私服单机搭建教程
  11. 怎么使用水经注万能地图下载器制作百度行政区划个性化地图
  12. 大数据和云计算到底是何关系?
  13. eureka-client无法启动com.netflix.discovery.DiscoveryClient : Shutting down DiscoveryClient
  14. 计算机双显卡关掉一个,怎么关掉集成显卡_win10双显卡电脑关闭集成显卡的方法...
  15. 游戏玩到这种程度,酱紫真的好吗?
  16. Cocos Creator 微信登录授权按钮适配
  17. 同城容灾、异地容灾、 双活 数据中心、 两地三中心的区别
  18. 螃蟹芯片RTL8762之修改蓝牙设备类型
  19. 【python】详解pandas.DataFrame.resample根据时间聚合采样(一)
  20. 程序员恭喜了!11月起逼自己拿下这个证,年薪68万起!

热门文章

  1. 微软全部正版软件下载地址和序列号索取
  2. 关于JS引擎效率的怨念
  3. TIOBE 2011年7月编程语言排行榜:Objective-C成为年度语言
  4. YUMI~~强大的USB启动盘制作工具!!
  5. 几个shell小脚本
  6. 微软11月份安全补丁更新 最高级别:重要
  7. 前端趋势榜:上周最 yyds 的 10 大前端项目 - 211101
  8. C++ string的使用
  9. reactjs redux入门完整版示例:store reducer getState dispatch subscribe action
  10. gitlab备份与恢复操作整理