考虑一个联盟,其成员共享一个共同的基类:
struct Base {
int common;
};
struct DerivedA : Base {};
struct DerivedB : Base {};
union Union {
DerivedA a;
DerivedB b;
};
无论联合在运行时“包含”什么(即,最后存储的值是什么),只要它包含某些东西,那就是Base的子类.那么有没有办法合法地使用这个想法来访问Base字段,而不知道存储在union中的对象的实际类型?
也许是这样的:
Base* p = reinterpret_cast<Base*>(&u);
… 可能不是.也许这个:
Base* p2 = static_cast<Base *>(&u.a);
如果u.b是最后存储的值,这是合法的吗?
我知道有关于适用于工会的“共同初始序列”的特殊规则,但不清楚基类是否有类似的东西.
显然它不适用于多重继承,所以也许这表明它根本不起作用.
解决方法:
完全按照键入它的示例实际上是有效的,但它不允许进行许多有用的更改.
对于union的非活动成员的任何部分,唯一有效的左值到右值转换是使用活动成员([class.mem] / 23)访问该成员的公共初始序列的一部分.
但是,常见的初始序列仅为两个标准布局结构([class.mem] / 20)定义,并且有很多规则可以作为标准布局结构([class] / 7).总结:
>该课程可能不是多态的.
>该类可能没有多个具有相同类型的基类.
>该类可能没有引用类型的非静态成员.
>该类的所有非静态成员都具有相同的访问控制.
>所有非静态成员(包括继承成员)首先在同一个类中声明.
>所有基类和非静态成员(包括继承成员)都以递归方式遵守所有上述规则.
>有些规则表明标准布局结构的第一个非静态成员与结构具有相同的地址,并且标准布局联合的所有非静态成员都具有相同的联合地址.但是,如果这些规则的任何组合意味着两个相同类型的对象必须具有相同的地址,则包含的struct / union不是标准布局.
(有关此最后一条规则的示例:
struct A {}; // Standard-layout
struct B { A a; }; // Standard-layout (and &b==&b.a)
union U { A a; B b; }; // Not standard-layout: &u.a==&u.b.a ??
struct C { U u; }; // Not standard-layout: U is not.
)
您的DerivedA和DerivedB都是标准布局,因此允许它们具有共同的初始序列.实际上,该公共序列是每个的单个int成员,因此它们实际上是完全布局兼容的(因此可以是包含这两个结构的一些其他结构的公共初始序列的一部分).
然而,这里更棘手的事情之一是关于属于同一类的所有成员的规则.如果将任何非静态成员添加到DerivedA和/或DerivedB,即使您向两者添加相同类型的成员,更改的结构也将不再是标准布局,因此没有共同点初始序列.这限制了您希望在此模式中使用继承的大多数现实原因.