C++:虚函数的实现

前言

继承、封装、多态是C++作为OO语言的三大特性。在学习C++的过程中,我们都对虚函数机制实现多态有或多或少的了解。尽管在日常的编程中,我们可能掌握了虚函数的特性并熟练地将其运用在项目中又或者根本搞不来C++而对虚函数望而生畏。别慌!本文将从底层揭秘虚函数究竟是怎么操作的,在运行过程中究竟执行的是什么样的代码。话不多说,搞快点!

环境

  • 操作系统:macOS Mojave 10.14.5
  • 编译器:Apple LLVM version 10.0.1 (clang-1001.0.46.4)
  • 工具:Hopper Disassembler v4

正文

虚函数是啥?

class A
{
public:
    int a;
    int b;
    virtual void f() {}
};

class B : public A
{
public:
    int x;
    int y;
    void f() override {}
};

int main()
{
    B b;
    A *x = &b;
    x->f();
    return 0;
}

先让我们来看看简单的一段代码,main函数中实例化了一个派生类B的对象,然后使用基类指针去指向该对象,当该指针调用f成员的时候,调用的并不是基类A的成员函数而是派生类B的成员函数。原来如此!基类指针似乎能够根据其真正指向的对象类型来调用实际重载过的函数,这就是虚函数机制嘛!!?

那么问题来了,这到底是如何实现的?可以通过编译器静态编译实现嘛?答案是不行的,比如我们随手写一手辣鸡代码。

... // 重用上述 class A B
int main()
{
    int x;
    A* p;
    A  a;
    B  b;
    while(cin >> x)
    {
        p = x > 0 ? &a : &b;
        p->f();
    }
    return 0;
}

我们无法在运行前知晓p所指向的真正类型,因此必须有合适的方法来解决这一问题。我们在学习过程中也听说过虚函数表(vtable)、动态绑定(dynamic binding)等名词,据说是用来实现虚函数的,那么其中的魔法究竟是怎么样的呢?让我们来深入了解一下!

虚函数表是啥?

之前我们就一直提到要深入了解深入了解,那么究竟是多深入呢?那自然是要通过反汇编来瞧一瞧啦!这里我们使用最开始的一段代码来分析。

main函数

首先我们注意到地址为0x0000000100000edf的指令lea rdi, qword [rbp+var_20],这条指令等价于rdi = rbp+var_20rbp+var_20是一个内存地址,而[rbp+var_20]代表该地址上的内容,qword指的是这个地址开始的包含8字节的内存空间),而这个地址正是B b的地址。下面我们进入派生类B的构造函数中观察构造函数(call __ZN1BC1Ev)如何构造这一对象。(mov指令可以理解为把右边的值赋给左边)

这里先关注一下此时堆栈的情况:

                   _____________________________
                  |                             |                      高地址
rbp ----->        |                             |                        |
                  |_____________________________|                        |
                  |                             |                        |    堆栈向下增长
                  |                             |                        |
                  |_
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值