【问题标题】:Size of virtual pointer-C++虚拟指针的大小-C++
【发布时间】:2009-10-21 23:14:47
【问题描述】:

C++ 中虚拟表的虚拟指针 (VPTR) 的大小是多少?这也不是作业问题...只是我在阅读 C++ 书籍时想到的一个问题。

【问题讨论】:

  • 这显然不是功课。讲师通常不会问这类问题,至少在本科阶段不会。
  • 你在说什么指针? VPTR 并不是一个标准的命名法。您是否对存储在每个对象中的 to vtbl 指针感兴趣?或者您对构成vtbl 本身的指针感兴趣。
  • @Leon:或者在任何级别,因为它是一个在编译器之间不一致的实现细节。也不是所有的编译器都使用 V-Tables 来实现虚函数(它恰好是最简单的技术)。
  • @Andrey T:我说的是每个对象中存储的指向 vtbl 的指针。

标签: c++ pointers vtable


【解决方案1】:

与此主题相关的优秀文章是Member Function Pointers and the Fastest Possible C++ Delegates。本文深入探讨了许多不同编译器的成员函数指针的实现。本文讨论了 vtable 指针的所有细微差别,特别是考虑到多重(和虚拟)继承。

【解决方案2】:

请注意,为了优雅地处理多重继承,一个对象中可以有多个 VPTR,但通常每个都可能是一个简单的体系结构相关指针。

尝试运行类似这样的东西,看看你的编译器是如何布局的:

#include <iostream>
using namespace std;

struct Base
{
    int B;
    virtual ~Base() {} 
};

struct Base2
{
    int B2;
    virtual ~Base2() {} 
};

struct Derived : public Base, public Base2
{
    int D;
};

int main(int argc, char* argv[])
{
    cout << "Base:" << sizeof (Base) << endl;
    cout << "Base2:" << sizeof (Base2) << endl;
    cout << "Derived:" << sizeof (Derived) << endl;

    Derived *d = new Derived();
    cout << d << endl;
    cout << static_cast<Base*>(d) << endl;
    cout << &(d->B) << endl;
    cout << static_cast<Base2*>(d) << endl;
    cout << &(d->B2) << endl;
    cout << &(d->D) << endl;
    delete d;
    return 0;
}

在我的 32 位编译器上,这为两个基类提供 8 个字节,为派生类提供 20 个字节(编译为 64 位时这些值加倍):

4 bytes Derived/Base VPTR
4 bytes int B
4 bytes Derived/Base2 VPTR
4 bytes int B2
4 bytes int D

您可以通过查看前 8 个字节了解如何将 Derived 视为 Base,以及如何通过查看后 8 个字节将其视为 Base2。

【讨论】:

    【解决方案3】:

    这取决于您的实施,但很容易找到。对于这个程序

    #include <iostream>
    
    struct virtual_base {
        int data;
        virtual_base() {}
        virtual ~virtual_base() {}
    };
    
    struct non_virtual_base {
        int data;
        non_virtual_base() {}
        ~non_virtual_base() {}
    };
    
    int main() {
        std::cout << sizeof( virtual_base ) - sizeof( non_virtual_base ) << '\n';
        return 0;
    }
    

    mine (VC 2008) 将打印 4,因此在这种情况下,多态性的成本是 4 字节。

    【讨论】:

      【解决方案4】:

      可能与普通指针大小相同...在 32 位机器上通常为 4 个字节。但这将取决于编译器,一些编译器可能会做不同的事情。

      【讨论】:

        【解决方案5】:

        很可能是任何其他指针的大小。试试这样的方法来找出你的编译器和机器:

        #include <iostream>
        struct base {
            base() {}
            virtual ~base() {}
        };
        int main( int argc, char **argv ) {
            std::cout << sizeof( base ) << std::endl;
        }
        

        【讨论】:

          【解决方案6】:

          虚函数表中的指针一般与系统中的常规指针大小相同。通常为每种类型计算一个虚函数表,并且每个对象实例都将包含指向其类型表的指针,因此包含虚函数的对象实例将比不包含虚函数的实例多使用 sizeof(void *) 字节。从多个基类型派生的类型必须可转换为任何基类型,因此可以根据需要包含指向基类型的虚函数表的多个指针。当然,所有这些都取决于编译器。

          【讨论】:

            猜你喜欢
            • 2021-06-22
            • 2012-06-08
            • 1970-01-01
            • 1970-01-01
            • 2018-09-01
            • 2017-01-01
            • 2012-02-14
            • 2013-10-13
            • 1970-01-01
            相关资源
            最近更新 更多