在C ++中使用union
的经验有限,我很难理解向该数据类型转换的基本机制。
假设两种类型Type_a
和Type_b
分别是int
和long
类型的包装。
联合定义为:
union Type_u {
Type_a a;
Type_b b;
}
现在我有Type_a
类型的东西,我们称之为j
(只是为了让人困惑)。我需要将它传递给一个需要Type_u
类型参数的函数:
void burninate(Type_u peasants);
将此变量j
传递给burninate
的正确方法是什么? (我遇到了将j
转换为Type_u
以及按原样传递的问题。两者都没有编译。)
值得指出的是,我无法修改联合类型(或Type_a或Type_b或者burninate的签名。)
答案 0 :(得分:4)
由于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);
答案 1 :(得分:2)
您可以像这样((Type_u)j)
传递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 T.a:10 T.b:10
答案 2 :(得分:1)
C ++通常不会鼓励使用联合,如果联盟成员拥有非平凡的构造函数和析构函数,它可能会特别尴尬,因为在这种情况下,union的自己的构造函数(分别是析构函数)将会被删除,如果你需要,你必须自己提供一个(你通常这样做)。
总的来说,将非POD类型放入联合可能不是一个好主意,因为语义很尴尬;一般来说,你不能为一个尚未构造的对象赋值,并且,虽然你可以使用placement new来构造一个union的成员,但是你无法真正知道该成员之前没有被构造过。 。此外,如果一个成员有一个明确的,非平凡的析构函数,你可以为union提供一个显式的析构函数,它可以显式地调用成员的析构函数,但是如何知道它是否必须这样做呢?
但是,如果您的工会成员是POD,那么您很好,但您仍然无法将工会转换为工会的成员或成员类型。 (GCC允许将其作为C扩展,但afaik g++
不会以相同的方式扩展C ++。)
但是,没有什么可以阻止你给union
一个构造函数。例如:
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);
// ...
}
如果你不能将构造函数添加到union类型的定义中,我认为你能做的最好的事情就是定义一个make_union
函数,为每个成员类型适当地覆盖它。
答案 3 :(得分:0)
Unions的工作方式与结构完全相同(唯一的区别是对象在内存中的分配方式)。所以你有Type_u U; Type_a j; U.a = j;博恩奈特(U);