sizeof class with int , function, virtual function in C++?

27,485

Solution 1

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 |

Solution 2

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.

Solution 3

  • 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.

Share:
27,485
user1002288
Author by

user1002288

Updated on June 01, 2020

Comments

  • user1002288
    user1002288 almost 4 years

    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

  • R. Martinho Fernandes
    R. Martinho Fernandes about 12 years
    sizeof(uint8_t) == 1 (there's no other possibility), sizeof(char[100]) == 100, etc.
  • Mooing Duck
    Mooing Duck about 12 years
    Padding should probably be mentioned too.
  • Luchian Grigore
    Luchian Grigore about 12 years
    @R.MartinhoFernandes what's sizeof char[53]?
  • Luchian Grigore
    Luchian Grigore about 12 years
    "That's the size of int" - not really. That's the size of int on his platform.
  • CygnusX1
    CygnusX1 about 12 years
    Everything is on his platform. Although this is not standard, in most modern compilers int is a 32-bit integer taking 4 bytes. Same goes for empty structs taking 1 byte, etc... I think in the answer to this question it is unnecessary to dwell into platform variety and compiler-implementation specifics.
  • Luchian Grigore
    Luchian Grigore about 12 years
    On the contrary. For a beginner it's very important to understand what is and isn't platform specific.
  • CygnusX1
    CygnusX1 about 12 years
    ... but beginner will most likely not work on a system that has non-32-bit integers in any foreseeable future. And when he does, he will be much better educated to know what is and what is not platform specific.
  • Luchian Grigore
    Luchian Grigore about 12 years
    I don't understand why people would argue that it's okay to say something that is clearly incorrect just because it's very common, or the person asking doesn't need to know the details at this stage, instead of just editing the answer to make it correct.
  • R. Martinho Fernandes
    R. Martinho Fernandes about 12 years
    @Luchian that wouldn't compile because it needs parentheses, but sizeof(char[53]) is guaranteed to be 53.
  • Martin York
    Martin York about 12 years
    sizeof(D)==8: Caused by compiler specific data structure used to implement virtual functions (potentially a vtable but not necessarily).
  • CygnusX1
    CygnusX1 about 12 years
    because trying to be perfectly accurate with everything can convey much more information than it is needed and may render the message difficult to understand. Imagine teaching Einstein's theory of relativity without explaining Newton's laws just because the latter is incorrect at relativistic speeds. On the contrary; you usually don't even mention Einstein until very very late.
  • Luchian Grigore
    Luchian Grigore about 12 years
    @CygnusX1 when I was taught Newtonian physics, the teacher started by saying, I think during every lecture, that it applies to small speeds. This was in 5th grade. I am serious. Romanians... I think any teacher that would try to teach it otherwise is wrong. You don't need to specify relativity, but you should say it's not always true.
  • yyny
    yyny almost 9 years
    In C++ standards, sizeof(char[100]) is most likely guaranteed 100 (Can someone give me a conformation?), in C it is defined as "AT LEAST 100", where all modern platforms return 100 (Windows, Linux, etc