美文网首页代码世界C++程序员
C++虚函数表的内容分析

C++虚函数表的内容分析

作者: CodingCode | 来源:发表于2017-06-04 15:01 被阅读109次

这篇文章继续分析C++虚函数表的内容,以及它的工作原理,即用户代码如何访问虚函数表的内容。

下面C++代码定义了一个类AAAA,main()函数new了一个对象,然后delete对象,我们按照调用顺序分析虚函数表的建立,关联等等操作。

#include <stdio.h>
#include <string>

class AAAA {
private:
    long l;
public:
    virtual void foo() {}
    virtual ~AAAA() {}
};

int main(int argc, char * argv[]) {
    AAAA * a = new AAAA();

    delete a;
    return 0;
}

从main()函数入口,主要有两条指令new一个AAAA对象,然后删除这个对象。

AAAA * a = new AAAA()

new指令生成的汇编指令如下:


    movl    $16, %edi
    call    _Znwm                         # operator new(unsigned long)
    movq    %rax, %rbx
    movq    %rbx, %rax
    movq    $0, (%rax)                #set instance buffer to 0
    movq    $0, 8(%rax)              # set instance buffer to 0
    movq    %rax, %rdi                # move instance pointer to %rdi for calling
    call    _ZN4AAAAC1Ev         # AAAA::AAAA()

主要有个三块功能,1. new一个16字节的内存,2. 内存初始化成0,3. 调用构造函数AAAA::AAAA(),即_ZN4AAAAC1Ev。
我们再看构造函数AAAA::AAAA()的代码:

_ZN4AAAAC1Ev:               # AAAA::AAAA()
    pushq   %rbp
    movq    %rsp, %rbp
    movq    %rdi, -8(%rbp)
    movq    -8(%rbp), %rax
    movq    $_ZTV4AAAA+16, (%rax)
    leave
    ret

在C++源代码里面,我们并没有为AAAA定义自己的构造函数,所以这个函数是缺省的构造函数,主要功能就一句话,把$_ZTV4AAAA+16的值赋值到对象实例的前8个字节(movq $_ZTV4AAAA+16, (%rax))。

再来看_ZTV4AAAA+16是个什么内容:

_ZTV4AAAA:                                              # vtable for AAAA
    .quad   0
    .quad   _ZTI4AAAA                               # typeinfo for AAAA
    .quad   _ZN4AAAA3fooEv
    .quad   _ZN4AAAAD1Ev
    .quad   _ZN4AAAAD0Ev
_ZTS4AAAA:                                             # typeinfo name for AAAA
    .string "4AAAA"
_ZTI4AAAA:                                              # typeinfo for AAAA
    .quad   _ZTVN10__cxxabiv117__class_type_infoE+16
    .quad   _ZTS4AAAA                             # typeinfo name for AAAA

上述代码都有编译器在翻译类AAAA的时候生成。我们看到_ZTV4AAAA是类AAAA的虚函数表地址,$_ZTV4AAAA+16指向的是虚函数AAAA:::foo()的地址;我们已经知道C++类对象内容的前八个字节是指向类虚函数表的指针,可是此时我们看到它并不是指向虚函数表首地址,而是指向首地址+16的一个偏移,为什么这样做呢?其实+16是第一个虚函数的地址,前面的16字节(+8字节指向类类型信息,+0我也不清楚其用处)保留属于C++类管理内部使用的,对用户而言可以隐藏,所以在使用者的角度看来,虚函数表就是按顺序从头开始排列的(+16偏移开始即可。

总结一句话,缺省构造函数就是把类的虚函数表地址写到类对象的前面8个字节地址。

下面我们看删除一个对象的函数

delete a;

delete指令生成汇编语言代码如下:

    movq    -24(%rbp), %rax
    movq    (%rax), %rax
    addq    $16, %rax
    movq    (%rax), %rdx
    movq    -24(%rbp), %rax
    movq    %rax, %rdi
    call    *%rdx

这段汇编代码的目的只有一个就是call到%rdx里面去,完成两件事,1.给%rdx找到正确的值,2.找到正确的函数参数。%rdx需要找到的值是析构函数的地址,参数当然是对象本身指针了。

从上述代码我们看到赋给%rdx的值是虚函数表+16的地址,看前面_ZTV4AAAA的定义,(+16)的地址就是指向第三个虚函数的地址,即_ZN4AAAAD0Ev


_ZN4AAAAD0Ev:           # AAAA::~AAAA()
    pushq   %rbp
    movq    %rsp, %rbp
    subq    $16, %rsp
    movq    %rdi, -8(%rbp)
    movq    -8(%rbp), %rax
    movq    %rax, %rdi
    call    _ZN4AAAAD1Ev
    movq    -8(%rbp), %rax
    movq    %rax, %rdi
    call    _ZdlPv
    leave
    ret

这个函数主要功能是调用另一个函数 _ZN4AAAAD1Ev

_ZN4AAAAD1Ev:           # AAAA::~AAAA()
    pushq   %rbp
    movq    %rsp, %rbp
    subq    $16, %rsp
    movq    %rdi, -8(%rbp)
    movq    -8(%rbp), %rax
    movq    $_ZTV4AAAA+16, (%rax)
    movq    -8(%rbp), %rax
    movq    %rax, %rdi
    call    _ZdlPv
    leave
    ret

函数_ZN4AAAAD1Ev是用户定义的析构函数,因为没有具体功能;也不清楚它具体要干什么,只看到最后它调用了一个delete函数。

上述代码可能比较复杂啰嗦,但是我们清楚了一个重要概念,即每一个多态类实例对象的起始地址都是一个指向虚函数表的指针,所有类的虚函数都在这个表中占用一列;这个地址的前面一个指针指向类的类型信息定义,从而从一个对象指针我们就能查到其类类型定义;这也是typeid和dyanmic_cast能够工作的原理。

1.jpg

最后说明一点在类_ZTV4AAAA的虚函数表中定义有两个析构函数,不知道为什么。

相关文章

  • Boolan_C++面向对象高级编程(下)_第二周笔记

    1、 对象模型:关于vptr(虚函数表指针)和vtbl(虚函数表) 1.1 课堂内容总结 (1)class中有虚函...

  • C++虚函数表的内容分析

    这篇文章继续分析C++虚函数表的内容,以及它的工作原理,即用户代码如何访问虚函数表的内容。 下面C++代码定义了一...

  • (Boolan) 面向对象高级编程(下)第四周笔记

    一、虚函数表 对C++ 虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)...

  • (Boolan) 面向对象高级编程(下)第四周笔记

    一、虚函数表 对C++虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来...

  • C++虚函数表(多态的实现)

    多态是C++的三大特性之一,是通过虚函数表来实现的。关于虚函数表: 每个含有虚函数的类都有一张虚函数表(vtbl)...

  • 虚函数表

    虚函数表对C++ 了解的人都应该知道虚函数(Virtual Function)是通过一张虚函数表(Virtual ...

  • 查漏补缺

    C++虚函数: 多态: 静态多态(重载)、动态多态(虚函数) 虚函数 虚函数表:编译器为每个类创建了一个虚函数表...

  • C++多态——虚函数表vtable

    纯Swift类的函数调用原理,类似于C++的虚函数表 纯Swift类的函数调用,类似于C++的虚函数表,是编译时决...

  • 虚函数

    文章内容转自关于C++中虚函数表存放位置的思考 作者:fuliangcheng 1、虚函数表vtable在Linu...

  • C++虚函数表

    虚函数表 C++中虚函数是通过一张虚函数表(Virtual Table)来实现的,在这个表中,主要是一个类的虚函数...

网友评论

    本文标题:C++虚函数表的内容分析

    本文链接:https://www.haomeiwen.com/subject/nzvvfxtx.html