gpt4 book ai didi

c++ - 如何在类中的其他 vtable 指针中选择 vtable 指针?

转载 作者:行者123 更新时间:2023-12-03 18:49:11 25 4
gpt4 key购买 nike

我对 virtual inheritance 很感兴趣这件事给我带来了神秘感。让我们以 virtual inheritance 为例。 :

struct Base {
virtual void v() { std::cout << "v"; }
};

struct IntermediateDerivedFirst : virtual Base {
virtual void w() { std::cout << "w"; }
};

struct IntermediateDerivedSecond : virtual Base {
virtual void x() { std::cout << "x"; }
};

struct Derived : IntermediateDerivedFirst, IntermediateDerivedSecond {
virtual void y() { std::cout << "y"; }
};
最后, Derived应该是这样的:
 --------
|[vtable]| -----> [ vbase offset 20 ]
|[vtable]|--- [ top offset 0 ]
|[vtable]|- | [ Derived typeinfo ]
-------- || [ IntermediateDerivedFirst::w() ]
|| [ Derived::y() ]
||
|----> [ vbase offset 12 ]
| [ top offset -8 ]
| [ Derived typeinfo ]
| [ IntermediateDerivedSecond::x()]
|
-----> [ vbase offset 0 ]
[ top offset -20 ]
[ Derived typeinfo ]
[ Base::v() ]

所以,从字面上看, virtual继承 Action vtable对于最基础的类,我们可以看到—— vtable代表 IntermediateDerivedFirst , IntermediateDerivedSecond不包含 Base 的地址的 v()方法。好的,那么,我们可以看到该类有几个 vtable s。
让我们考虑一个代码:
IntermediateDerivedFirst* fb = new Derived;
fb->v();
delete fb;
此调用仍然有效, 然而 , vtable对于 IntermediateDerivedFirst没有关于 v() 的信息方法,它似乎在这里使用了一些魔法,它使用了第三个 vtable调用指针 v() .
那么,编译器如何选择需要的 vtable获取被调用函数地址的指针?

最佳答案

Bjarne Stroustroup 写了一篇关于使用 C++ 解决多重继承中的“菱形继承(钻石问题)”的详细论文:
Stroustrup, B Fall 1989, 'Multiple Inheritance for C++'. Computing Systems, Vol. 2 No. 4, p. 367-395
在两个 IntermediateDerived 类中声明了“虚拟基础”;保证您只获得公共(public)基类的单个实例。
来自 C++ Language / Classes / Derived classes

For each distinct base class that is specified virtual, the most derived object contains only one base class subobject of that type, even if the class appears many times in the inheritance hierarchy (as long as it is inherited virtual every time).


也就是说,编译器将为每个提供一个实例:
  • 派生
  • 中级派生优先
  • 中级派生第二
  • 基地

  • 两个 IntermediateDerived_X 类都有 虚拟指针 在他们的 vtables 中存储了 Base 类的偏移量。当任一 IntermediateDerived_X 类尝试访问 Base::v() 时,它使用 虚拟指针 在它的 vtable 中找到 Base 对象。沿着这条线;如果 Derived 继承了 100 个以上具有相同“虚拟基础”的 IntermediateDerived_X 类,则仍然只有一个 Base 实例。
    对 Base::v() 函数的调用使用虚拟指针来访问 Base 类的实例。
    重要的是要注意 Base 对象只被构造一次;当它在 Derived 类中首次初始化时。继承的类将从 Base 构造到大多数派生类。反过来;破坏的顺序将从大多数派生到基础
    在示例实例化中;调用“new Derived”将构造四个类中的每一个的单个实例。
    根据上面的地址表:IntermediateDerivedFirst 知道'vbase offset = 20',这是Base object vtable 的位置。 IntermediateDerivedSecond 可以以相同的方式访问 Base 类(vbase offset = 12);并会产生完全相同的功能。 没有神奇的第三个 vtable,而只是一个指向在所有派生类之间共享的 Base 的 vtable 的指针。
    从实现的角度来看;在所有虚拟类中添加一个指向基类的单个指针通常比将虚拟表复制到每个派生类更节省内存。不同的编译器、优化器、链接器等可能会稍微不同地实现或更改生成的 vtable。但是所有使用虚拟继承的派生类都只会指向一个 Base 对象。

    关于c++ - 如何在类中的其他 vtable 指针中选择 vtable 指针?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67248308/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com