谁能给我解释一下这是怎么回事?首先,我认为大多数程序员都知道带有虚函数的类有一个 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/