Search code examples
c++classinheritancecastingstandards

Pointer-interconvertibility of derived and base class objects and the Standard's wording on it


I'm trying to understand when I can safely cast a derived object to a base subobject through a pointer to void (I think it should be the same as reinterpret_cast). But the Standard's wording on this, which I could find, confuses me. First of all,

Two objects a and b are pointer-interconvertible if:

— one is a standard-layout class object and the other is the first non-static data member of that object, or, if the object has no non-static data members, the first base class subobject of that object

From this one cannot draw a reliable conclusion whether "or" applies to the whole subsentence before "or" or only to the second part of it. This is important because I can't know for sure if "standard-layout class object" is imperative for pointer-interconvertibility with the base subobject in the case of absence of non-static data members.

But while digging in the Standard further I've found:

If a standard-layout class object has any non-static data members, its address is the same as the address of its first non-static data member. Otherwise, its address is the same as the address of its first base class subobject (if any).

This seems to be more clear that "standard-layout" is required. But still confusing. Consider the following code:

class B { public: int b; };
class C : public B { public: int c; };

int main ()
{ 
    C c;
    B* b = &c;
    std::cout << &c << " address of standard-layout class object\n";
    std::cout << &c.c << " address of its first non-static data member\n";
    std::cout << b << " address of first base class subobject\n";
    return 0;
}

On VS2019 the result is:

009BFBF8 address of standard-layout class object
009BFBFC address of its first non-static data member
009BFBF8 address of first base class subobject

which is not what the Standard says. Can you explain me this?


Solution

  • The point is in definition of standard-layout class. From http://www.cplusplus.com/reference/type_traits/is_standard_layout/:

    A standard-layout class is a class (defined with class, struct or union) that:

    • has no virtual functions and no virtual base classes.

    • has the same access control (private, protected, public) for all its non-static data members.

    • 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.

    • its base class (if any) is itself also a standard-layout class.

    • And, has no base classes of the same type as its first non-static data member.

    In you example class C does not match the third rule and so it is not a standard-layout class.

    Also, about your question about 'or', it applies only to the second part, i.e. after 'or' the statement is still about standard-layout class object, but without non-static members.