具有虚函数GCC / Xcode的类的大小

时间:2011-07-29 15:54:54

标签: c++ inheritance virtual sizeof

任何人都可以向我解释这里发生了什么吗?首先,我认为大多数程序员都知道具有虚函数的类具有vtbl,因此在其顶部有4个额外的字节。据我所知,这是相当标准的。我已经测试了这个,并利用这个事实,然后从带有修补vtbls的二进制文件加载到位。在过去的6个月里,我一直在Xcode工作,最近才遇到需要做一些加载的东西,所以我再次考虑修补vtbls。为了确保我的理解是正确的,我写了一个示例程序。这是:

class A
{
    public:
    virtual int getData()
    {
        return a;
    }

    virtual void print()
    {
        printf("hello\n");
    }
    int a;
};

class B : public A
{
public:
    int getData()
    {
        return b;
    }
    int b;
};

class C : public B
{
public:
    int getData()
    {
        return c;
    }

    void print()
    {
        printf("world\n");
    }
    int c;
 };

class D
{
public:
    int a;
    int b;
};

int main (int argc, const char * argv[])
{
    A* tA = new A();
    tA->a = 1;

    printf("A: %d\n", sizeof(A));
    printf("A data: %d\n", tA->getData());

    B* tB = new B();
    tB->a = 2;
    tB->b = 4;

    printf("B: %d\n", sizeof(B));
    printf("B data: %d\n", tB->getData());

    C* tC = new C();
    tC->c = 8;

    printf("C: %d\n", sizeof(C));
    printf("C data: %d\n", tC->getData());

    A* aC = tC;
    aC->print();

    printf("D: %d\n", sizeof(D));

    return 0;
}

我的预期输出是:

A:8

数据:1

B:12

B数据:4

C:16

C数据:8

世界

D:8

然而,我得到的输出是:

A:16

数据:1

B:16

B数据:4

C:24

C数据:8

世界

D:8

有人知道这里发生了什么吗?谢谢!

1 个答案:

答案 0 :(得分:3)

类A到C的实例包含vptr,指向动态类型的虚函数表的指针。此指针在64位计算机上占用8个字节(或在32位计算机上占用4个字节)。每个int成员占用4个字节。

sizeof(Class)的最小值是所有成员的sizeof(成员)的总和。如果是这样,那么

sizeof(A) = 8 (vptr) + 4 (int a) = 12
sizeof(B) = 8 (vptr) + 4 (int a) + 4 (int b) = 16
sizeof(C) = 8 (vptr) + 4 (int a) + 4 (int b) + 4 (int c) = 20
sizeof(D) = 4 (int a) + 4 (int b) = 8

但是,这只是最小尺寸。编译器通常会将此大小增加到sizeof(void *)的倍数,这里是8个字节。此过程称为对齐。看起来这可能会浪费内存,但性能提升会超过这一点:CPU可以比非对齐数据更快地读取对齐数据。

顺便说一句,如果您使用的是32位计算机,那么您的预期结果将是正确的。指针(特别是vptr)在那里是4字节宽,并且对齐也是4字节的倍数。由于所讨论的类的所有数据成员都是4字节大,因此对齐不会在那里做任何事情。