为什么工会静态成员不存储为工会?

时间:2019-04-05 17:25:03

标签: c++ union static-members

在C ++中,union可以包含静态成员,这些静态成员与类一样属于一个类,因此对于所有对象都是公用的。

union U
{
   long l;
   int i;
   static long sl;
   static int si;
};

int U::si;
long U::sl;

逻辑上期望所有联合静态成员存储在与非静态成员存储类似的相同地址上。但事实并非如此。一个简单的示例显示静态成员存储在不同的地址下,并且可以包含独立值。

int main()
{
   U u;
   u.si = 10;
   u.sl = 50;

   std::cout << "Non-static members adresses: " << &u.i << " " << &u.l << std::endl;
   std::cout << "Static members adresses: " << &u.si << " " << &u.sl << std::endl;
   std::cout << "Static members values: " << u.si << " " << u.sl << std::endl;
   return 0;
}

输出:

Non-static members adresses: 006FF8EC 006FF8EC
Static members adresses: 00AEB144 00AEB140
Static members values: 10 50

我不明白为什么在联合中保留了独立的值存储。我认为这具有误导性,没有任何意义。不过,在我看来,这是有原因的。 union静态成员的目的是什么?

2 个答案:

答案 0 :(得分:7)

您可以从两个角度来看这个问题。

C ++观点:

工会首先是一个阶级。它的目的不同于班级,但它是由班级告知的。

联合是一类,在任何一种类型中,联合的一个子对象仅是活动的。为此,它更改了联合的成员子对象的工作方式。这也是为什么联合不能具有基类子对象的部分原因。

静态数据成员不是成员子对象,因此它们在联合中的布置应与它们在非工会类中的布置无异。

此外,C ++中类型的静态成员实际上只是函数和对象名称的作用域机制。它们仍然有效地是全局的,但是它们可以是私有的也可以是隐藏的,并且必须在它们的类型名前面加上前缀,以便您使用它们。

并集的静态数据成员的行为与类的静态数据成员的行为完全没有任何意义。

C ++必须与C兼容:

联盟存在于C中,因此C ++也必须拥有它们。但是联合很难在C ++对象模型中定义,使用起来很麻烦,还有很多其他事情。因此,您可以将并集视为C ++需要但不愿处理的事情。那么您如何处理它们?

在处理C工会的工作方式时,使工会像C一样工作。 C中没有静态成员这样的东西,因此没有C代码期望将静态联合成员组合在一起。因此...不要将它们结合在一起。如果用户确实需要一个静态成员,该静态成员是某些类型的集合的并集,则他们可以轻松地创建一个并创建该类型的单个静态成员。

因此,通过使静态成员有所不同,用户不会失去任何表达能力。

答案 1 :(得分:2)

联合是一次[basic.compound]p1.6 [class]p7 [class.union]最多容纳一个数据成员的类,它们的静态数据成员没有特别的规则。其余的类类型(即classstruct)。

因此,静态数据成员的行为与所有类相同。

如果您想拥有一个由多个类型的并集组成的静态数据成员,则可以执行以下操作:

union U {
    long l;
    int i;

    union {
        long l;
        int i;
    } static s;
};

decltype(U::s) U::s;

// They are the same indeed
static_assert(&U().s.l == &U().s.l);

您将需要通过s来引用元素,例如不过,是s.l而不是sl