sizeof class with int , function, virtual function in C++?
This is an online C++ test question, which has been done.
#include<iostream>
using namespace std;
class A
{
};
class B
{
int i;
};
class C
{
void foo();
};
class D
{
virtual void foo();
};
class E
{
int i ;
virtual void foo();
};
class F
{
int i;
void foo();
};
class G
{
void foo();
int i;
void foo1();
};
class H
{
int i ;
virtual void foo();
virtual void foo1();
};
int main()
{
cout <<"sizeof(class A) : " << sizeof(A) << endl ;
cout <<"sizeof(class B) adding the member int i : " << sizeof(B) << endl ;
cout <<"sizeof(class C) adding the member void foo() : " << sizeof(C) << endl ;
cout <<"sizeof(class D) after making foo virtual : " << sizeof(D) << endl ;
cout <<"sizeof(class E) after adding foo virtual , int : " << sizeof(E) << endl ;
cout <<"sizeof(class F) after adding foo , int : " << sizeof(F) << endl ;
cout <<"sizeof(class G) after adding foo , int : " << sizeof(G) << endl ;
G g;
cout <<"sizeof(class G) after adding foo , int : " << sizeof(g) << endl ;
cout <<"sizeof(class H) after adding int 2 virtual " << sizeof(H) << endl ;
return 0;
}
output:
sizeof(class A) : 1
sizeof(class B) adding the member int i : 4
sizeof(class C) adding the member void foo() : 1
sizeof(class D) after making foo virtual : 8
sizeof(class E) after adding foo virtual , int : 16
sizeof(class F) after adding foo , int : 4
sizeof(class G) after adding foo , unsigned int : 4
sizeof(class g) after adding foo , unsigned int : 4
sizeof(class H) after adding int 2 virtual 16
My questions:
Why siszeof(A)
is 1 and sizeof(C)
is 1 too ?
Why siszeof(H)
is 16 but sizeof(G)
is 4 ?
Why siszeof(E)
is 16 but sizeof(F)
is 4 ?
Why siszeof(D)
is 8 but sizeof(E)
is 16 ?
My guess:
A virtual function is a pointer with 8 bytes.
But, I do not know why E
size is 16 ?
Adding a function to an empty class does not change its size ?
Any help is appreciated.
thanks
First off, a virtual function is not a pointer with 8 bytes. In C++ nothing but sizeof(char)
is guaranteed to be any number of bytes.
Second, only the first virtual function in a class increases its size (compiler-dependent, but on most - if not all - it's like this). All subsequent methods do not. Non-virtual functions do not affect the class's size.
This happens because a class instance doesn't hold pointers to methods themselves, but to a virtual function table, which is one per class.
So if you had:
class A
{
virtual void foo();
}
and
class B
{
virtual void goo();
virtual void test();
static void m();
void x();
}
you would have sizeof(A) == sizeof(B)
.
And now:
Why siszeof(A) is 1 and sizeof(C) is 1 too ?
A
and C
have size 1 just because it's not allowed for a class to be of size 0. The functions have nothing to do with it. It's just a dummy byte.
Why siszeof(H) is 16 but sizeof(G) is 4 ?
G
has only one member that accounts for memory - the int
. And on your platform, sizeof(int) == 4
. H
, besides the int
, also has a pointer to the vftable
(virtual function table, see above). The size of this, size of int and allignment are compiler specific.
Why siszeof(E) is 16 but sizeof(F) is 4 ?
Explained above - non virtual methods don't take up memory in the class.
Why siszeof(D) is 8 but sizeof(E) is 16 ?
D
only contains the vftable
pointer which is apparently 8 bytes on your platform. E
also has an int, and the vftable
is aligned to 8 bytes. So it's something like:
class E
4 bytes for int | 4 padding bytes | 8 bytes for vftable pointer |
| x | x | x | x | | | | | v | v | v | v | v | v | v | v |
Why siszeof(A) is 1 and sizeof(C) is 1 too ?
The function in C
is not virtual, so the class doesn't need a vtable pointer, so it needs no more storage than A
. Neither A
nor C
need any storage at all, but because language requires that different instances of the same class have different pointers, they can't have a size of zero - so the compiler makes them as small as it can, i.e. 1 byte.
Why siszeof(H) is 16 but sizeof(G) is 4 ?
G
has no virtual functions, so all it needs to store is the int, which on your compiler and architecture is 4 bytes.
H
has virtual functions, so the class needs to contain an int
and a vtable pointer. All widely used compilers store the vtable pointer at the start of the class, so the layout is {vptr, int}, which is 8+4=12 bytes if you're on a 64 bit host.
However, the compiler is free to pad this out to 16 bytes so that if multiple instances of H
are allocated in an array then all of them will be word-aligned. This is important because there are significant performance implications for accessing a pointer (i.e. the vtable pointer here) if it is not word-aligned.
Why siszeof(E) is 16 but sizeof(F) is 4 ?
E has virtual functions, so needs a vtable ptr, so its layout is just like H
's. F
has no virtual functions, it only has an int, so its layout is just like G
's. so the answer's the same as for G
and H
.
The ordering of the members/functions just doesn't matter here because there's only one member variable and the vtable ptr always goes first if there is one.
Why siszeof(D) is 8 but sizeof(E) is 16 ?
D
has no member variables, but it has a virtual function, so it needs a vtable pointer. The vtable pointer is the only thing it needs, so its size is sizeof(void*)
, which is 8 bytes. E
needs the same as D
, plus 4 bytes for an integer, and the compiler rounds it up to 16 bytes for alignment.
- sizeof(A)==1
It is so because of C++ standard which prohibits classes/structs of size 0. That's why an empty struct/class have size 1. I find it pretty annoying, but they had some reasoning for that.
- sizeof(B)==4
That's the size of int, plain and simple :)
- sizeof(C)==1
That's the size of an empty struct (see A). Nonvirtual functions do not contribute to the object size at all. There is nothing you need to store in an object to be able to call its nonvirtual member function.
- sizeof(D)==8
I am assuming that you are building a 64-bit application. Any class having at least 1 virtual function has a pointer to a virtual method table. This allows you to call a correct virtual function even if an object pointer was casted to some parent class. Often the pointer is referred to as a vtable. More reading at wiki: http://en.wikipedia.org/wiki/Virtual_method_table
I think the size 8 is coming from that 64-bit pointer.
- sizeof(E)==16
To store a pointer and an int you technically need 12 bytes. However, a pointer must be aligned to 8 bytes. Now envision yourself creating an array A of objects E. A[0].vtable
would have address &A+0, A[0].i
would be at &A+8
, A[1].vtable
would be at &A+12
-- woops, we have a problem, 12 is not divisable by 8. That's why compiler creates a padding. It adds additional useless bytes to make the object align correctly in an array. In this case, the lowest divisable by 8 number is 16. Hence the size.
- sizeof(F)==4
Same as in case of C - nonvirtual functions do not contribute at all to the size, so your size matches B.
sizeof(G)==4 -- same as F
sizeof(H)==16
The number of virtual functions does not matter. There is still only one vtable pointer in your object. If you put more virtual functions, the virtual table gets larger, but not the object itself. In many object-oriented programs you often end up with lots of virtual functions. Having pointers stored directly in the object itself would be wasteful.
That's why the size (and the explanation) of H matches the size of E.