struct X { int i; };
struct Y : X { Y(); }; // non-trivial
struct A { int a; };
struct B : public A { int j; Y y; }; // non-trivial
extern B bobj;
B* pb = &bobj; // OK
int* p1 = &bobj.a; // undefined, refers to base class member
int* p2 = &bobj.y.i; // undefined, refers to member's member
A* pa = &bobj; // undefined, upcast to a base class type
B bobj; // definition of bobj
extern X xobj;
int* p3 = &xobj.i; // OK, X is a trivial class
X xobj;
struct W { int j; };
struct X : public virtual W { };
struct Y {
int* p;
X x;
Y() : p(&x.j) { // undefined, x is not yet constructed
}
};
struct A { };
struct B : virtual A { };
struct C : B { };
struct D : virtual A { D(A*); };
struct X { X(A*); };
struct E : C, D, X {
E() : D(this), // undefined: upcast from E* to A* might use path E* → D* → A*
// but D is not constructed
// “D((C*)this)” would be defined: E* → C* is defined because E() has started,
// and C* → A* is defined because C is fully constructed
X(this) {} // defined: upon construction of X, C/B/D/A sublattice is fully constructed
}; — end example
struct V {
virtual void f();
virtual void g();
};
struct A : virtual V {
virtual void f();
};
struct B : virtual V {
virtual void g();
B(V*, A*);
};
struct D : A, B {
virtual void f();
virtual void g();
D() : B((A*)this, this) { }
};
B::B(V* v, A* a) {
f(); // calls V::f, not A::f
g(); // calls B::g, not D::g
v->g(); // v is base of B, the call is well-defined, calls B::g
a->f(); // undefined behavior, a's type not a base of B
} — end example
struct V {
virtual void f();
};
struct A : virtual V { };
struct B : virtual V {
B(V*, A*);
};
struct D : A, B {
D() : B((A*)this, this) { }
};
B::B(V* v, A* a) {
typeid(*this); // type_info for B
typeid(*v); // well-defined: *v has type V, a base of B yields type_info for B
typeid(*a); // undefined behavior: type A not a base of B
dynamic_cast<B*>(v); // well-defined: v of type V*, V base of B results in B*
dynamic_cast<B*>(a); // undefined behavior, a has type A*, A not a base of B
} — end example