52
votes

Suppose I have a base class with some member variables and no virtual functions:

class Base {
   int member;
};

and a derived class that derives in a non-virtual way from Base and has no new member variables an again no virtual functions:

class Derived : Base {
};

Obviously sizeof(Derived) can't be smaller than sizeof(Base).

Is sizeof(Derived) required to be equal to sizeof(Base)?

4
Interesting question (+1). I don't know the answer, but don't really see why the standard would go out of its way to require this.NPE
I'm not even sure that there is a guarantee in the standard that Derived can't be smaller than Base, if the empty base class rules are used.James Kanze
@AaronMcDaid In practice or in theory? In practice, I doubt it (but you can add data members to D, and still end up with sizeof(D) == sizeof(B)). But the standard doesn't prevent it; one could imagine an implementation where the size were in some way dependent on the name. (But I feel fairly confident that you'll never actually see such an implementation, and I don't worry about a loss of portability if my code doesn't take this possibility into account.)James Kanze
Related: stackoverflow.com/q/19843816/420683 (which is a stricter requirement)dyp
@HansPassant: I know about that and this is why I explicitly stated that in this question there're no virtual methods and no virtual inheritance.sharptooth

4 Answers

18
votes

From 5.3.2 [expr.sizeof]

When applied to a class, the result [of sizeof] is the number of bytes in an object of that class including any padding required for placing objects of that type in an array. The size of a most derived class shall be greater than zero (1.8).

From 1.8 [intro.object]

Unless it is a bit-field (9.6), a most derived object shall have a non-zero size and shall occupy one or more bytes of storage. Base class sub-objects may have zero size. An object of POD type (3.9) shall occupy contiguous bytes of storage.

and a note:

The actual size of a base class subobject may be less than the result of applying sizeof to the subobject, due to virtual base classes and less strict padding requirements on base class subobjects.

Put these together and I think what it's telling you is that you have no guarantees whatsoever as to what sizeof might tell you, other than the result will be greater than zero. In fact, it doesn't even seem to guarantee that sizeof(Derived) >= sizeof(Base)!

13
votes

There is no such requirement.

The only relevant part of the language I can think of is that every object, whether complete or not, and whether most-derived or not, has an identity, which is given by the pair of its address and its type. Cf. C++11 1.8/6:

Two objects that are not bit-fields may have the same address if one is a subobject of the other, or if at least one is a base class subobject of zero size and they are of different types; otherwise, they shall have distinct addresses.

So both the most-derived object and the base subobject of your example must have distinct identities.

It would certainly make sense for a compiler to give both Base and Derived a size of 1, but this is not mandatory. It would be acceptable if the Base had size 1729 and Derived had size 2875.

10
votes

Interesting question. I have an example where a derived class with an extra field is the same size as an empty base class. (This should be a comment but is much too large; please accept one of the other answers, although upvotes are welcome if it's interesting.)

Consider this trivial C++ program:

class A {};

class B : public A {
    int m_iInteger;
};

int _tmain(int argc, _TCHAR* argv[])
{
    printf("A: %d\r\n", sizeof(A));
    printf("B: %d\r\n", sizeof(B));
    printf("int: %d\r\n", sizeof(int));

    return 0;
}

What would you expect the output to be, if sizeof(int) is 4? Perhaps something like:

A: 0
B: 4
int: 4

?

My compiler - Embarcadero C++ Builder 2010 - gives the output:

A: 8
B: 8
int: 4

In other words, adding an extra field in the derived class does not make the derived class bigger.

There is some insight into why with the help file topic on the compatibility option Zero-length empty base class.

Usually the size of a class is at least one byte, even if the class does not define any data members. When you set this option, the compiler ignores this unused byte for the memory layout and the total size of any derived classes; empty base classes do not consume space in derived classes. Default = False

It appears that the size of a class with default compiler settings for this compiler is 8 bytes, not one, and in fact changing this setting for this code example has no effect.

You may also find this article on base class sizes and the above optimization interesting. It discusses why classes must have a size of at least one byte, what the optimization does, and delves into representation of member functions etc too:

Indeed, the standard requires that the size of an object shall never be zero; it also requires that in a derived object data members of the base class(es) shall appear before user-declared data members of the derived class. However, a base class subobject isn’t considered a complete object. Therefore, it’s possible to remove the base class subobject from the derived object without violating the rules. In other words, in the object t, the offset of S and x may overlap...

Please read the article for the full context of that quote.

-1
votes
class Base {
 // int member;            I have just created an empty base class.
};

class Derived : Base {
};

Now gcc compiler would give "size>0" for the both the objects created by Base and Derived classes. gcc compiler just provides the presence of address for the objects to the user.

  Note:Derived class would contain base class members, so obviously we can think of 
  sizeof(derived class) greater then sizeof(base class). But this depends on the compiler 
  if it allocates some extra space while defining the derived class. 

My present gcc compiler showed the sizeof objects of both Base and Derived to be same.