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

标签 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;
}

我的预期输出是:

答:8

A数据:1

乙:12

B数据:4

中:16

C数据:8

世界

直径:8

但是,我得到的输出是:

答:16

A数据:1

乙:16

B数据:4

C:24

C数据:8

世界

直径:8

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

最佳答案

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

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

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 字节大,因此对齐不会在那里做任何事情。

关于c++ - 具有虚函数的类的大小 GCC/Xcode,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6875783/

相关文章:

c# - 通用列表上的 is-operator

c# - 从库中覆盖方法

c++ - 如何更改 QTableWidget 的最小尺寸?

c++ - 使用 "if constexpr"和 SFINAE 禁用分支

java - 如何在子类中访问父类(super class)的 protected 方法?

C++ 纯虚void

windows - 大内存块分配和 4K block

c++ - 如何用非虚函数覆盖虚函数?

c++ - 使用gcc在C中链接C++静态库

c++ - 是否可以更改临时对象并将其作为参数传递?