无论存储的类型如何,是否允许访问联合成员的公共基础 class?
Is it allowed to access a common base class of union members regardless of the stored type?
考虑一个联盟,其成员共享一个共同的基础 class:
struct Base {
int common;
};
struct DerivedA : Base {};
struct DerivedB : Base {};
union Union {
DerivedA a;
DerivedB b;
};
无论联合 "contains" 在运行时是什么(即最后存储的值是什么),只要它包含一些东西,那东西就是 Base
的子class .那么有没有什么方法可以合法地使用这个想法来访问 Base
字段,而不知道联合中存储的对象的实际类型?
可能是这样的:
Base* p = reinterpret_cast<Base*>(&u);
...可能不会。也许是这样:
Base* p2 = static_cast<Base *>(&u.a);
如果u.b
是最后一次存储的值是否合法?
我知道 "common initial sequences" 有适用于联合的特殊规则,但不清楚基础 class 是否有类似的规则。
显然它不适用于多重继承,所以这可能表明它根本不起作用。
只要使用的结构是标准布局,通过任何包含该基的成员访问基 class 都是合法的。
在您提供的示例中,结构是标准布局,因此您可以通过 u.a
或 u.b
.
访问基础
您输入的示例实际上是有效的,但它不允许进行很多有用的更改。
联合非活动成员的任何部分唯一有效的左值到右值转换是访问该成员与活动成员公共初始序列的一部分 ([class.mem]/23) .
但是只为两个标准布局结构 ([class.mem]/20) 定义了公共初始序列,并且对于什么符合标准布局结构 ([class]/7).总结:
class可能不是多态的。
class不能有超过1个相同类型的碱基class。
class 可能没有引用类型的非静态成员。
class 的所有非静态成员具有相同的访问控制。
包括继承成员在内的所有非静态成员首先在同一个 class.
中声明
所有基 classes 和非静态成员包括继承成员递归地遵守上述所有规则。
有规则说标准布局结构的第一个非静态成员与结构具有相同的地址,并且标准布局联合的所有非静态成员都具有工会的相同地址。但是,如果这些规则的任何组合意味着相同类型的两个对象必须具有相同的地址,则包含 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
成员,因此它们实际上是完全布局兼容的(因此可能是包含这两个结构的其他一对结构的公共初始序列的一部分)。
不过,这里比较棘手的事情之一是所有成员属于同一 class 的规则。如果向 DerivedA
and/or DerivedB
添加任何非静态成员,即使向两者添加相同类型的成员,更改后的结构 is/are 没有更长的标准布局,所以没有共同的初始序列。这限制了您希望在此模式中使用继承的大多数现实原因。
考虑一个联盟,其成员共享一个共同的基础 class:
struct Base {
int common;
};
struct DerivedA : Base {};
struct DerivedB : Base {};
union Union {
DerivedA a;
DerivedB b;
};
无论联合 "contains" 在运行时是什么(即最后存储的值是什么),只要它包含一些东西,那东西就是 Base
的子class .那么有没有什么方法可以合法地使用这个想法来访问 Base
字段,而不知道联合中存储的对象的实际类型?
可能是这样的:
Base* p = reinterpret_cast<Base*>(&u);
...可能不会。也许是这样:
Base* p2 = static_cast<Base *>(&u.a);
如果u.b
是最后一次存储的值是否合法?
我知道 "common initial sequences" 有适用于联合的特殊规则,但不清楚基础 class 是否有类似的规则。
显然它不适用于多重继承,所以这可能表明它根本不起作用。
只要使用的结构是标准布局,通过任何包含该基的成员访问基 class 都是合法的。
在您提供的示例中,结构是标准布局,因此您可以通过 u.a
或 u.b
.
您输入的示例实际上是有效的,但它不允许进行很多有用的更改。
联合非活动成员的任何部分唯一有效的左值到右值转换是访问该成员与活动成员公共初始序列的一部分 ([class.mem]/23) .
但是只为两个标准布局结构 ([class.mem]/20) 定义了公共初始序列,并且对于什么符合标准布局结构 ([class]/7).总结:
class可能不是多态的。
class不能有超过1个相同类型的碱基class。
class 可能没有引用类型的非静态成员。
class 的所有非静态成员具有相同的访问控制。
包括继承成员在内的所有非静态成员首先在同一个 class.
中声明
所有基 classes 和非静态成员包括继承成员递归地遵守上述所有规则。
有规则说标准布局结构的第一个非静态成员与结构具有相同的地址,并且标准布局联合的所有非静态成员都具有工会的相同地址。但是,如果这些规则的任何组合意味着相同类型的两个对象必须具有相同的地址,则包含 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
成员,因此它们实际上是完全布局兼容的(因此可能是包含这两个结构的其他一对结构的公共初始序列的一部分)。
不过,这里比较棘手的事情之一是所有成员属于同一 class 的规则。如果向 DerivedA
and/or DerivedB
添加任何非静态成员,即使向两者添加相同类型的成员,更改后的结构 is/are 没有更长的标准布局,所以没有共同的初始序列。这限制了您希望在此模式中使用继承的大多数现实原因。