开发者

C++ vtordisp的应用场景分析

目录
  • 问题代码
  • 1. 基本概念回顾
  • 2. 应用场景
    • 虚继承与虚函数并存的类层次结构
  • 3. 编译器相关考虑

    问题代码

    #include <IOStream>
    using namespace std;
    class base
    {
    public:
    	base() {}
    	virtual void show() { cout << "base:: show"<<endl; }
    private:
    	int ma;
    };
    class derive:virtual pubjavascriptlic base
    {
    public:
    	derive() {}
    	virtual void show() { cout << "derive:: show"; }
    private:
    	int mb;
    };
    int main()
    {
    	cout << sizeof(derive) << endl;
    }

    以上代码类大小常规来说应该是php如下,占16个字节大小,但是为何是20呢

    预期结构

    class derive    sizephp(16):
            +---
     0      | {vbptr}
     4      | mb
            +---
            +--- (virtual base base)
     8      | {vfptr}
    12      | ma
            +---

    实际结构,占大小20个字节

    class derive    size(20):
            +---
     0      | {vbptr}
     4      | mb
            +---
    8       | (vtordisp for VBAse base)
            +--- (virtual base base)
    12      | {vfptr}
    16      | ma
            +---
    derive::$vbtable@:
     0      | 0
     1      | 12 (derived(derive+0)base)
    derive::$vftable@:
            | -12
     0      | &(vtordisp) derive::show
    derive::show this adjustor: 12
    vbi:       class  offset o.vbptr  o.vbte fVtorDisp
                base      12       0       4 1

    C++ vtordisp的应用场景分析

    经过验证 必须满足以下两个条件

    • 派生类重写了虚基类的虚函数。
    • 派生类定义了构造函数或者析构函数。

    才会产生vtordisp.

    这就牵扯到vtordisp了,介绍如下

    1. 基本概念回顾

    在 C++ 中,当涉及虚继承时,为了确保在派生类对象中能正确定位虚基类的子对象(包含虚基类的数据成员、虚函数等内容),编译器会在派生类对象的内存布局中安排虚基类表指针等相关结构来记录偏移量信息,以实现准确访问虚基类部分。同时,对于有虚函数的类,会存在虚函数表(VTable)来支持多态调用。

    vtordisp 主要用于处理虚继承和虚函数结合场景下,构造函数和析构函数中对虚基类指针调整的一种机制,它本质上是编译器为了正确处理对象的初始化和析构顺序、保证虚基类相关操作的正确性而引入的一个额外的字节(在 32 位系统下通常是 4 字节,64 位系统下通常是 8 字节)来存储偏移量相关信息。

    2. 应用场景

    虚继承与虚函数并存的类层次结构

    • 场景描述:当类层次结构中既有虚继承又有类自身包含虚函数的情况时,在派生类的构造函数和析构函数中,需要准确地处理与虚基类相关的初始化和清理工作,同时还要考虑虚函数机制带来的多态性影响。

    3. 编译器相关考虑

    • 不同的编译器对于 vtordisp 的处理可能会有一些差异,有些编译器可能会根据具体的类层次结构复杂度、是否确实存在需要调整虚基类指针偏移量的情况等来决定是否启用 vtordisp 机制以及如何分配相应的字节来存储相关信息。比如在 Visual C++ 编译器中,对于符合特定条件的虚继承和虚函数结合的场景,会自动插入 vtordisp 相关代码来处理对象布局和操作顺序问题,而在 GCC 等其他编译器中,也有其对应的实现方式和判断标准来确保在类似场景下的代码正确性。

    如果不想要vtordisp 可以加 #pragma vtordisp(off) 进行关闭。

    vtordisp是Visual C++编译器的一个特性,主要用于解决在类继承中,虚函数的调用与对象布局的问题。当你在类中使用了虚函数,并且该类被继承,且继承类覆盖了基类的虚函数时,可能会出现所谓的"跳跃问题"(slicing problem)。

    "跳跃问题"是指当你有一个基类的指针指向派生类对象,并且调用了虚拟函数,预期是派生类的函数被调用,但实际上可能会调用基类的函数。这是因为编译器为了能够快速地调用虚拟函数,直接使用了指针的偏移量来计算虚拟函数的地址,而不是检查实际对象的类型。

    为了解决这个问题,当你在类中www.devze.com有一个或多个虚拟函数,并且类被继承,且派生类覆盖了基类的虚函数时,编译器可能会为类添加一个额外的隐藏成员,称为vtordisp字段。vtordisp字段的作用是在构造函数和析构函数执行过程中,记录对象的实际类型信息,以便正确地调用虚拟函数。具体由编译器进行管理。

    在网上搜集资料并未搞清楚其底层原理,请知道的大佬不吝赐教。

    到此这篇关于C++ vtordispjs的应用场景的文章就介绍到这了,更多相关C++ vtordisp应用内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜