c++ - 虚拟继承的虚拟函数表中的虚拟基址偏移量

标签 c++ c++11 virtual-inheritance

代码如下(在Ubuntu 16.04上用G++-5.4编译的C++11代码):

#include <iostream>

using namespace std;



class Base
{
    public:
        virtual void show()
        {
            cout << "Base" << endl;
        }

        virtual void func()
        {
            cout << "func in Base" << endl;
        }

    protected:
        int base = 15;
};

class A: public virtual Base
{
    public:
        void show() override
        {
            cout << this << endl;
            cout << 'A' << endl;
        }

        void func() override
        {
            cout << this << endl;
            cout << "func in A" << endl;
        }

    protected:
        int a = 31;
};



int main(int argc, const char *argv[])
{
    A obj_a;

    return 0;
}

我尝试使用 GDB 检查对象“obj_a”的内存布局(首先,我设置了“set print object on”、“set print pretty on”、“set print vtbl on”、“set print asm-demangle on "在 GDB 中):

(gdb) p sizeof(obj_a)
$1 = 32
(gdb) x/8aw &obj_a
0x7fffffffe320: 0x400d20 <vtable for A+24>  0x0 0x1f    0x0
0x7fffffffe330: 0x400d50 <vtable for A+72>  0x0 0xf 0x0

我们可以知道obj_a的开头和它的virtual base subobject之间的偏移量是16B(virtual base offset)。然后我检查 A 的由 0x400d08 (0x400d20 - 24) 指向的虚函数表:

(gdb) x/14ag 0x400d08
0x400d08 <vtable for A>:    0x10    0x0
0x400d18 <vtable for A+16>: 0x400d90 <typeinfo for A>   0x400b46 <A::show()>
0x400d28 <vtable for A+32>: 0x400b98 <A::func()>    0xfffffffffffffff0
0x400d38 <vtable for A+48>: 0xfffffffffffffff0  0xfffffffffffffff0
0x400d48 <vtable for A+64>: 0x400d90 <typeinfo for A>   0x400b8f <virtual thunk to A::show()>
0x400d58 <vtable for A+80>: 0x400be1 <virtual thunk to A::func()>          0x400d20 <vtable for A+24>
0x400d68 <VTT for A+8>: 0x400d50 <vtable for A+72>  0x0

正如我们所见,有两个“virtual thunk to xxx”,即“0x400b8f”和“0x400be1”。我查看了这两个地址。

(gdb) x/3i 0x400b8f
0x400b8f <virtual thunk to A::show()>:  mov    (%rdi),%r10
0x400b92 <virtual thunk to A::show()+3>:    add    -0x18(%r10),%rdi
0x400b96 <virtual thunk to A::show()+7>:    jmp    0x400b46 <A::show()>
(gdb) x/3i 0x400be1
0x400be1 <virtual thunk to A::func()>:  mov    (%rdi),%r10
0x400be4 <virtual thunk to A::func()+3>:    add    -0x20(%r10),%rdi
0x400be8 <virtual thunk to A::func()+7>:    jmp    0x400b98 <A::func()>

我的问题是:“add -0x18(%r10),%rdi”和“add -0x20(%r10),%rdi”到底是什么意思?为什么是 -24 (-0x18) 和 -32 (-0x20)? (我觉得应该都是-16)

最佳答案

谢谢 Rerito,对此感到抱歉。

我的问题是我对汇编代码不熟悉。

(gdb) x/3i 0x400b8f
0x400b8f <virtual thunk to A::show()>:  mov    (%rdi),%r10
0x400b92 <virtual thunk to A::show()+3>:    add    -0x18(%r10),%rdi
0x400b96 <virtual thunk to A::show()+7>:    jmp    0x400b46 <A::show()>

在“virtual thunk to A::show()”的汇编代码中,%rdi 保存了“this”值。 "mov (%rdi),%r10"表示移动 "vptr"值(它的地址是 "this")到 r10 寄存器。 “add -0x18(%r10),%rdi”表示将地址为“vptr - 24”(即虚拟表中的0xffffffffffffffff0)的值添加到“this”。所以“这个”值可以更正为 A 的对象的地址。

关于c++ - 虚拟继承的虚拟函数表中的虚拟基址偏移量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40627476/

相关文章:

c++ - memory_order_relaxed 无法按 C++ 并发实际代码中的预期工作

c++ - 不同类的不可访问基面向对象编程c++

c++ - 多重或虚拟继承下的类的内存布局和vtable(s)?

c++ - 大多数派生类如果未实现虚函数则无法编译,但如果一个基类未实现虚函数则可以编译

c++ - 声明内部类和友元的多个源文件

c++ - 从 Streambuffer 转换的字符串中的垃圾打印

c++ - pdb 文件,检查磁盘空间不足、路径无效或权限不足

c++ - 使用 shared_from_this 时出现 std::bad_weak_ptr 异常

c++ - 在返回的 XML 上循环映射以获取节点值

c++ - 具有模板化类成员函数的多线程