3
#include <iostream>
class SuperBase
{
public:
    int Sb;
};
class Base1:virtual public SuperBase
{
public:
    int a;
};
class Base2:virtual public SuperBase
{
public:
    int b;
};
class Derived: public Base1,public Base2
{
public:
    int c;

};
int main()
{
    using namespace std;
    cout<<sizeof(Derived);
    return 0;
}



output is showing 24
but it should show 20 because
int sb 4 bytes
int a 4 bytes
int b 4 bytes
int c 4 bytes
vbptr 4 bytes
total 20 bytes

as we are using virtual inheritance concept so int sb should not be calculated twice isn't?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Suri
  • 3,287
  • 9
  • 45
  • 75

5 Answers5

4

24 is probably:

  • 4 for Sb
  • 4 for a
  • 4 for b
  • 4 for c
  • 8 for the overhead of virtual inheritance.

On my (32bit) compiler, sizeof(Derived) is 24 and sizeof(Base1) is 12, though, suggesting that the overhead isn't always 8.

I would guess that the 8 consists of one vtable (or similar) pointer at the start of the Base1 subobject, and another one in the Base2 subobject, which will be used when a pointer to the object is cast to Base2*. The issue with multiple inheritance is that the offset of Base1 from the start of the object can't be the same as the offset of Base2 from the start of the object.

In particular, this means that for one of Base1 and Base2, the offset when its a base class subobject of Derived is different from when BaseN is the most derived class. But when you cast to Base2*, the resulting value must point to something that "looks like" a Base2. Hence there's some extra overhead in cases where virtual inheritance actually results in a shared base class.

Another way to do it would just be to make sizeof(SuperBase) 4, sizeof(Base1) and sizoef(Base2) both 12 (two ints and a vtable pointer), and sizeof(Derived) equal to 28: 4 for Sb, 4 each for a,b,c, and 4 each for three vtable pointers, one each in Base1, Base2 and Derived. But your compiler has (I think) done you a favour, and arranged for Derived's vtable pointer to be in the same place as that for Base1, as is normal with single inheritance.

In all cases when I say "vtable pointer", it may or may not be the exact same thing that's used for virtual functions, but it's some kind of class meta-data. Perhaps it's just a pointer or offset used to reach a base class.

I drew some little diagrams here that might help:

Why can't you use offsetof on non-POD structures in C++?

Community
  • 1
  • 1
Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • -1 size of Sb has to be irrelevant since it is inherited virtually. – Šimon Tóth Dec 02 '10 at 12:52
  • @Let_Me_Be: What do you mean, irrelevant? If Sb was a `char[1000]`, would you still expect the size of the object to be 24? Well, it isn't. – Steve Jessop Dec 02 '10 at 12:54
  • Huh, I guess I have been working with a completely wrong explanation of virtual inheritance for the last 5 years. What the heck? – Šimon Tóth Dec 02 '10 at 12:57
  • 1
    @Let_Me_Be: yes, virtual inheritance is not an exception to the rule that an object's members and base class subobjects all occupy a single block of memory. It just adds a mechanism to ensure that the base class subobject can be shared, and still always be found. – Steve Jessop Dec 02 '10 at 13:04
2

Typically classes that inherit with virtual inheritance from other classes need an extra pointer or offset to point to something that indicates where each virtual base that they inherit from is located. Depending on the type of the complete object that they are part of, virtual bases can't be assumed to be in the same relative location.

The pointer need not actually point at the base class itself, the compiler might insert the id of a type information structure that can be used to work out the complete layout of the object, but typically something is needed so that when code that uses a class like Base1 through a pointer or reference it will always work regardless of the complete object which that particular Base belongs to.

This means that the size of Base1 and Base2 in Derived are likely to be something like sizeof(int) + sizeof(void*), 8 bytes on a typical 32-bit compiler in addition to the size of SuperBase and the member of Derived for the total size of Derived.

CB Bailey
  • 755,051
  • 104
  • 632
  • 656
1

Remember to look at ALL the sizes - it makes it easier to see what might be going on.

In this case, on the compiler I tested on having a virtual base class adds 4 bytes of overhead to each of Base1 and Base2.

SuperBase           4
Base1               12
Base2               12
Derived             24
Mike G.
  • 1,670
  • 11
  • 17
0

Bit Padding maybe?

http://en.wikipedia.org/wiki/Data_structure_alignment#Typical_alignment_of_C_structs_on_x86

Maybe it is that.

0

I don't think you can make assumptions about the sizes of the compiler-generated parts of a class. On my compiler (GCC 4.4.5), sizeof(SuperBase) is 4, sizeof(Base1) and sizeof(Base2) are both 16, and sizeof(Derived) is 40.

Wyzard
  • 33,849
  • 3
  • 67
  • 87