So why is C the same size of B?
Because trailing padding of B
was reused for C::b
. The padding can be reused because B
is not a POD (plain old data) class (because it is not a standard layout class).
Although it seems that B used the 3 byte padding in A.
The padding of A
cannot be reused for other sub objects of B
, because A
is a standard layout class and is trivially copyable i.e. A
is a POD class.
will the padding of base class be copied into the derived class?
I suppose that you didn't mean to ask about copying, but are rather whether the base class sub object of a derived class will have the same padding as the individual type.
The answer is, as might be deduced from the above: The padding will be same, except the trailing padding may be re-used for other sub objects, unless the base class is a POD, in which case its padding can not be reused.
In the case where the padding may be reused, whether it will be is not specified by the standard, and there are differences between compilers.
Please explain or link to a definition of "standard layout types".
Current standard draft:
[basic.types]
... Scalar types, standard-layout class types ([class.prop]), arrays of such types and cv-qualified versions of these types are collectively called standard-layout types.
[class.prop] (in older versions of the standard, these may be found under [class] directly)
A class S is a standard-layout class if it:
(3.1) has no non-static data members of type non-standard-layout class (or array of such types) or reference,
(3.2) has no virtual functions and no virtual base classes,
(3.3) has the same access control for all non-static data members,
(3.4) has no non-standard-layout base classes,
(3.5) has at most one base class subobject of any given type,
(3.6) has all non-static data members and bit-fields in the class and its base classes first declared in the same class, and
(3.7) has no element of the set M(S) of types as a base class, where for any type X, M(X) is defined as follows.107 [ Note: M(X) is the
set of the types of all non-base-class subobjects that may be at a
zero offset in X. — end note]
(3.7.1) If X is a non-union class type with no (possibly inherited) non-static data members, the set M(X) is empty.
(3.7.2) If X is a non-union class type with a non-static data member of type X0 that is either of zero size or is the first
non-static data member of X (where said member may be an anonymous
union), the set M(X) consists of X0 and the elements of M(X0).
(3.7.3) If X is a union type, the set M(X) is the union of all M(Ui) and the set containing all Ui, where each Ui is the type of the
ith non-static data member of X.
(3.7.4) If X is an array type with element type Xe, the set M(X) consists of Xe and the elements of M(Xe).
(3.7.5) If X is a non-class, non-array type, the set M(X) is empty.
Item (3.6) applies in this case. Some members of B are not first declared in B. In particular, B::A::valA, and B::A::a are declared first in A. A friendlier way to describe the rule is: The class must have either no direct members, or none of its ancestors must have members. In this case both the base and the derived class have members, so it is not standard layout.