是否允许访问联合成员的公共基类,而不管存储的类型如何

Is it allowed to access a common base class of union members regardless of the stored type?

本文关键字:基类 不管 存储 类型 是否 许访问 访问 成员      更新时间:2023-10-16

考虑一个联合,其成员共享一个公共基类:

struct Base {
int common;
};
struct DerivedA : Base {};
struct DerivedB : Base {};
union Union {
DerivedA a;
DerivedB b;
};

无论并集在运行时"包含"什么(即,上次存储的值是什么),只要它包含一些东西,那个东西就是Base的子类。那么,在不知道联合中存储的对象的实际类型的情况下,有没有任何方法可以合法地使用这个想法来访问Base字段?

也许类似于:

Base* p = reinterpret_cast<Base*>(&u);

可能不会。也许这个:

Base* p2 = static_cast<Base *>(&u.a);

如果u.b是最后存储的值,这合法吗?

我知道有一些关于"公共初始序列"的特殊规则适用于并集,但不清楚基类是否有类似的规则。

很明显,它不适用于多重继承,所以这可能表明它根本不起作用。

您键入的示例实际上是有效的,但它不允许进行许多有用的更改。

在并集的非活动成员的任何部分上,唯一有效的左值到右值转换是访问该成员与活动成员的公共初始序列的一部分([class.mem]/23)。

但是,公共初始序列只为两个标准布局结构([class.mem]/20)定义,并且有相当多的规则可以作为标准布局结构来定义([class]/7)。总结:

  • 类可能不是多态的。

  • 该类不能有多个具有相同类型的基类。

  • 类不能具有引用类型的非静态成员。

  • 类的所有非静态成员都具有相同的访问控制。

  • 包括继承成员在内的所有非静态成员首先在同一类中声明。

  • 所有基类和非静态成员(包括继承的成员)都递归地遵守上述所有规则。

  • 有一些规则规定,标准布局结构的第一个非静态成员与该结构具有相同的地址,并且标准布局联合的所有非静态成员都具有相同的联合地址。但是,如果这些规则的任何组合都意味着同一类型的两个对象必须具有相同的地址,那么包含的结构/联合就不是标准布局。

(例如最后一条规则:

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.

)

您的DerivedADerivedB都是标准布局,因此允许它们具有共同的初始序列。事实上,该公共序列是每个结构的单个int成员,因此它们实际上是完全布局兼容的(因此可能是包含这两个结构的其他结构对的公共初始序列的一部分)。

然而,这里更棘手的事情之一是关于所有成员属于同一个类的规则。如果向DerivedA和/或DerivedB添加任何非静态成员,即使向两者添加相同类型的成员,更改后的结构也不再是标准布局,因此没有通用的初始序列。这限制了您希望在此模式中使用继承的大多数现实原因。

通过包含基类的任何成员访问基类是合法的,前提是所使用的结构是标准布局。

在您提供的示例中,结构是标准布局,因此您可以通过u.au.b访问基础。