At first glance, this looks like undefined behavior…
#include <iostream>
struct SomeBaseClass
{
// ...
};
struct MyFakerClass
{
SomeBaseClass base;
void foo() { std::cout << "hello" << std::endl; }
};
int main()
{
MyFakerClass c;
MyFakerClass *p = static_cast<MyFakerClass *>(static_cast<void *>(&c.base));
p->foo();
}
… but if the first field of an object is guaranteed to have the same address as the object, then this must be safe, right? Or is there some other rule that intervenes?
(C++11, §9.2, ¶21)
So, this is safe as long as a class is “standard-layout”, i.e.:
(C++11, §9, ¶7)
All the requirements about the virtual stuff are because of the vptr: as said above, many compilers put it as a first hidden member, but they are allowed to put it anywhere or, if they are able, to omit it at all or implement virtual dispatch in other ways, so virtual in general alters the layout of the class in an unspecified way.
The “same access control clause” is because
(C++11, §9.2, ¶15)
I suppose that this may be to allow compilers to reorder/group the members of a class by access-control (i.e. inside the compiler the IR of a class may contain a list for the members under each access-control specifier, which does not allow to keep the original ordering – all the interleaved public/private/protected sections would be grouped and e.g. the private members may be put in front of the class by default).
The no non-standard-layout members/base classes “recursive” clauses are to ensure that the class is standard-layout as a whole (base classes and members are a part of it).
Additional details on why the rest of this stuff can affect the layout of the class may be found in §9.2.
Notice that this is a weaker condition than the class being POD (as I incorrectly said in the comment above), since a class is POD if it is both standard layout and trivial (§9 ¶10)