Can anyone explain to me what is going on here? First off, I think most programmers know that a class with a virtual function has a vtbl and thus has 4 extra bytes on the top of it. As far as I know, that's fairly standard. I've tested this and taken advantage of this fact before to do load in place from a binary file with patched vtbls. For the last 6 months, I've been working in Xcode and just recently came across the need to do some load in place stuff, so I was looking into patching vtbls again. Just to make sure my understanding was correct, I wrote a sample program. Here it is:
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;
}
My expected output was:
A: 8
A data: 1
B: 12
B data: 4
C: 16
C data: 8
world
D: 8
However, the output I'm getting is:
A: 16
A data: 1
B: 16
B data: 4
C: 24
C data: 8
world
D: 8
Anybody have any idea what's going on here? Thanks!
Instances of classes A through C contain a vptr, a pointer to the virtual function table for the dynamic type. This pointer occupies 8 bytes on your 64-bit machine (or 4 bytes on a 32-bit machine). Each int member takes up 4 bytes.
The minimum value of sizeof(Class) is the sum of sizeof(member) for all members. If it were like that, then
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
However, this is only the minimum size. Compilers usually increase this size to a multiple of sizeof(void*), which is 8 bytes here. This process is called aligning. It may look like this wastes memory, but this is outweighed by a performance gain: The CPU can read aligned data much faster than non-aligned data.
By the way, your expected result would have been correct if you were on a 32-bit machine. Pointers (esp. vptr) are 4 bytes wide there, and alignment is also to multiples of 4 bytes. Since all data members of the classes in question are 4 bytes big then, alignment wouldn't do anything there.
精彩评论