6

在 C++ 中使用 s 的经验有限union,我很难理解转换为/从该数据类型转换的基本机制。

假设有两种类型Type_a和分别是类型和Type_b的包装器。intlong

联合定义为:

union Type_u {
    Type_a a;
    Type_b b;
}

现在我有一些 type Type_a,让我们称之为j(只是为了混淆)。我需要将它传递给需要类型参数的函数Type_u

void burninate(Type_u peasants);

j将此变量传递给的正确方法是什么burninate?(我遇到了转换j和按Type_u原样传递的问题。都没有编译。)

值得指出的是,我无法修改联合类型(或 Type_a 或 Type_b 或 burninate 的签名。)

4

4 回答 4

8

因为Type_a是第一个元素,你可以像这样初始化一个联合:

Type_a j;
Type_u u = {j};
burninate(u);

如果你想传递一个类型Type_b

Type_b k;
Type_u u;
u.b = k;
burninate(u);

这在 C 和 C++ 中是有区别的。在 C99 中,您可以使用指定的初始化程序来初始化不是第一个的元素。

Type_b k;
Type_u u = {.b = k};
burninate(u);
于 2013-11-09T02:42:49.403 回答
4

你可以像这样传递 j((Type_u)j)并且它会起作用。

[编辑] 当这些家伙表示难以置信时,这里是代码示例尝试编译这段代码,它会像一个魅力一样工作。

#include <stdio.h>
typedef union type_u {
    int a;
    long b;
}type;

int main ()
{
type T;
int j = 10;

    T = ((type)j);

    printf ("T.a:%d T.b:%lu \n", T.a, T.b);

return 0;
}

见 o/p XXX-mac:~ jork$ gcc union_test.c XXX-mac:~ jork$ ./a.out Ta:10 Tb:10

于 2013-11-09T02:41:17.743 回答
1

C++ 通常不会特意鼓励使用联合,如果联合成员有非平凡的构造函数和析构函数,这可能会特别尴尬,因为在这种情况下联合自己的构造函数(分别为析构函数)将被删除并且如果您需要一个(您通常会这样做),您必须自己提供一个。

总的来说,将非 POD 类型放入联合中可能不是一个好主意,因为语义很尴尬;通常,您不能为尚未构造的对象分配值,并且虽然您可以使用placement new 来构造联合的成员,但您无法真正知道该成员以前没有被构造. 此外,如果成员具有显式且非平凡的析构函数,您可以为联合提供显式析构函数,它可以显式调用成员的析构函数,但它如何知道它是否必须这样做?

但是,如果您的工会成员是 POD,那么您很好,但是您仍然不能将工会强制转换为成员或将会员类型强制转换为工会。(GCC 允许将其作为 C 扩展,但 afaikg++不会以相同的方式扩展 C++。)

尽管如此,没有什么能阻止你给uniona 构造函数。例如:

union long_or_double {
  long a;
  double d;

  long_or_double(long l) : a(l) {}
  long_or_double(int i) : a(i) {}
  // etc.
  long_or_double(double d) : d(d) {}
};

int f(long_or_double u);

int main(int argc, char** argv) {
  // Both of these work, because there is an explicit constructor
  f(argc);
  f(3.7);
  // ...
}

如果你不能在联合类型的定义中添加构造函数,我认为你能做的最好的事情就是定义一个make_union函数,为每个成员类型适当地覆盖它。

于 2013-11-09T03:23:23.823 回答
0

联合的工作方式与结构完全一样(唯一的区别是对象在内存中的分配方式)。所以你有 Type_u U; 类型_a j; Ua = j; 燃烧(U);

于 2013-11-09T03:02:03.283 回答