3
votes

This is basically a continuation of my prior question.

This is [class]/7 in C++14:

A standard-layout class is a class that:

  • (7.1) — has no non-static data members of type non-standard-layout class (or array of such types) or reference,
  • (7.2) — has no virtual functions (10.3) and no virtual base classes (10.1),
  • (7.3) — has the same access control (Clause 11) for all non-static data members,
  • (7.4) — has no non-standard-layout base classes,
  • (7.5) — either has no non-static data members in the most derived class and at most one base class with non-static data members, or has no base classes with non-static data members, and
  • (7.6) — has no base classes of the same type as the first non-static data member.

Consider the following snippet:

struct B{ int i; };
struct A : B{ int j; };

A satisfies bullet points (7.1) thru (7.4), but doesn't satisfy (7.5), as A has a non-static data member and has a base class with a non-static data member.

What is the problem with A being a standard-layout class?

Edit

As far as I can understand the accepted answer to the question of which this is being considered a dupe, the snippet above would have undefined behavior, if I tried to cast a pointer to A to the first data member of the base class B and back, because of this sentence written by the OP:

Within a class, members are allocated in increasing addresses according to the declaration order. However C++ doesn't dictate the order of allocation for data members across classes.

But that doesn't seem to answer my question. Suppose for example that in a certain compiler implementation, base B would follow struct A in memory, instead of preceding it. But this would contradict the fact that there is an implicit conversion, from a pointer to a derived class, to a pointer to a base class, according to [conv.ptr]/3:

A prvalue of type “pointer to cv D”, where D is a class type, can be converted to a prvalue of type “pointer to cv B”, where B is a base class (Clause 10) of D.

That is, if the base B followed struct A in memory, the above implicit conversion would be invalid.

1
Why would the conversion be invalid? The conversion would just make the appropriate offset and give you the right pointer. - Barry
@Barry [conv.ptr]/3 does not say anything about an offset. Otherwise, if what you were correct, this would be possible: A a; A* p = &a; B* q = p; with q != p, i.e., a copy initialization, where the target q has a different value than the source p. - Alexander
That's definitely possible. Consider a class with two non-empty bases where you cast a pointer to the derived class to a pointer to the 2nd base. - Barry
@Barry You convinced me and also answered my question. Thanks for your insight. - Alexander

1 Answers

0
votes

Directly answering the question as phrased:

The purpose of this bullet is to allow very simple cases of inheritance where only one of the classes has data members.

Data layout for inheritance is unspecified, so the standard could just disallow inheritance altogether, but the standard makes an exception if one class has no data to treat the result still as Standard Layout.