5

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

4

6 回答 6

7

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

于 2009-10-21T23:27:05.480 回答
3

请注意,为了优雅地处理多重继承,一个对象中可以有多个 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。

于 2009-10-21T23:22:03.880 回答
2

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

#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 字节。

于 2009-10-22T08:00:49.603 回答
1

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

于 2009-10-21T23:18:02.777 回答
1

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

#include <iostream>
struct base {
    base() {}
    virtual ~base() {}
};
int main( int argc, char **argv ) {
    std::cout << sizeof( base ) << std::endl;
}
于 2009-10-21T23:20:35.580 回答
1

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

于 2009-10-21T23:22:24.470 回答