我学到了,但是没有真正的工会。我阅读的每一篇 C 或 C + + 文本都会介绍它们(有时是顺便介绍) ,但是它们往往很少给出为什么或在哪里使用它们的实际例子。在现代(甚至是传统)情况下,工会什么时候会有用?我唯一的两个猜测是,当您的工作空间非常有限,或者当您正在开发一个 API (或类似的东西) ,并且您希望强制最终用户一次只拥有多个对象/类型的一个实例时,将编写微处理器。这两个猜测是否接近正确?
struct my_variant_t {
int type;
union {
char char_value;
short short_value;
int int_value;
long long_value;
float float_value;
double double_value;
void* ptr_value;
};
};
然后你可以这样使用它:
/* construct a new float variant instance */
void init_float(struct my_variant_t* v, float initial_value) {
v->type = VAR_FLOAT;
v->float_value = initial_value;
}
/* Increments the value of the variant by the given int */
void inc_variant_by_int(struct my_variant_t* v, int n) {
switch (v->type) {
case VAR_FLOAT:
v->float_value += n;
break;
case VAR_INT:
v->int_value += n;
break;
...
}
}
union {
unsigned char byte_v[16];
long double ld_v;
}
使用这个声明,可以很简单地显示 long double的十六进制字节值,更改指数符号,确定它是否是非正态值,或者为不支持它的 CPU 实现长的双算术,等等。
当字段依赖于某些值时节省存储空间:
class person {
string name;
char gender; // M = male, F = female, O = other
union {
date vasectomized; // for males
int pregnancies; // for females
} gender_specific_data;
}
Grep the include files for use with your compiler. You'll find dozens to hundreds of uses of union:
[wally@zenetfedora ~]$ cd /usr/include
[wally@zenetfedora include]$ grep -w union *
a.out.h: union
argp.h: parsing options, getopt is called with the union of all the argp
bfd.h: union
bfd.h: union
bfd.h:union internal_auxent;
bfd.h: (bfd *, struct bfd_symbol *, int, union internal_auxent *);
bfd.h: union {
bfd.h: /* The value of the symbol. This really should be a union of a
bfd.h: union
bfd.h: union
bfdlink.h: /* A union of information depending upon the type. */
bfdlink.h: union
bfdlink.h: this field. This field is present in all of the union element
bfdlink.h: the union; this structure is a major space user in the
bfdlink.h: union
bfdlink.h: union
curses.h: union
db_cxx.h:// 4201: nameless struct/union
elf.h: union
elf.h: union
elf.h: union
elf.h: union
elf.h:typedef union
_G_config.h:typedef union
gcrypt.h: union
gcrypt.h: union
gcrypt.h: union
gmp-i386.h: union {
ieee754.h:union ieee754_float
ieee754.h:union ieee754_double
ieee754.h:union ieee854_long_double
ifaddrs.h: union
jpeglib.h: union {
ldap.h: union mod_vals_u {
ncurses.h: union
newt.h: union {
obstack.h: union
pi-file.h: union {
resolv.h: union {
signal.h:extern int sigqueue (__pid_t __pid, int __sig, __const union sigval __val)
stdlib.h:/* Lots of hair to allow traditional BSD use of `union wait'
stdlib.h: (__extension__ (((union { __typeof(status) __in; int __i; }) \
stdlib.h:/* This is the type of the argument to `wait'. The funky union
stdlib.h: causes redeclarations with either `int *' or `union wait *' to be
stdlib.h:typedef union
stdlib.h: union wait *__uptr;
stdlib.h: } __WAIT_STATUS __attribute__ ((__transparent_union__));
thread_db.h: union
thread_db.h: union
tiffio.h: union {
wchar.h: union
xf86drm.h:typedef union _drmVBlank {
class Vector
{
union
{
double _coord[3];
struct
{
double _x;
double _y;
double _z;
};
};
...
}
这允许我以数组或元素的形式访问数据。
我使用联合使不同的术语指向相同的值。在图像处理中,不管我是在处理列、宽度还是 X 方向的大小,它都会变得令人困惑。为了解决这个问题,我使用了一个联合,这样我就知道哪些描述是一起使用的。
union { // dimension from left to right // union for the left to right dimension
uint32_t m_width;
uint32_t m_sizeX;
uint32_t m_columns;
};
union { // dimension from top to bottom // union for the top to bottom dimension
uint32_t m_height;
uint32_t m_sizeY;
uint32_t m_rows;
};
struct Batman;
struct BaseballBat;
union Bat
{
Batman brucewayne;
BaseballBat club;
};
ReturnType1 f(void)
{
BaseballBat bb = {/* */};
Bat b;
b.club = bb;
// do something with b.club
}
ReturnType2 g(Bat& b)
{
// do something with b, but how do we know what's inside?
}
Bat returnsBat(void);
ReturnType3 h(void)
{
Bat b = returnsBat();
// do something with b, but how do we know what's inside?
}
因为 N可能会有所不同(我们可能希望将 Bx 类添加到混合中) ,而且这会导致构造函数出现混乱,还因为 A 对象会占用大量空间。
我们可以使用一个奇怪的容器,其中包含 void*指向 Bx对象的指针和类型强制转换来检索这些对象,但是这样做很难,而且是 C 风格的... ... 但是更重要的是,这会让我们有许多动态分配的对象的生命周期来管理。
相反,我们可以这样做:
union Bee
{
B1 b1;
.
.
.
Bn bn;
};
enum BeesTypes { TYPE_B1, ..., TYPE_BN };
class A
{
private:
std::unordered_map<int, Bee> data; // C++11, otherwise use std::map
public:
Bee get(int); // the implementation is obvious: get from the unordered map
};
因此,您节省了内存,更重要的是——您避免了对小对象(与通过类继承/多态性实现相比)的可能极端数量(如果您使用了大量运行时定义的数字)的任何动态分配。但是更有趣的是,您仍然可以使用 C + + 多态性的功能(例如,如果您喜欢双重分派;)来处理这种结构。只需将“虚拟”接口指针作为此结构的一个字段添加到所有数字类型的父类,指向 这个例子而不是/除了原始类型之外,或者使用好的老 C 函数指针。
struct NumberBase
{
virtual Add(NumberBase n);
...
}
struct NumberInt: Number
{
//implement methods assuming Number's union contains int
NumberBase Add(NumberBase n);
...
}
struct NumberDouble: Number
{
//implement methods assuming Number's union contains double
NumberBase Add(NumberBase n);
...
}
//e.t.c. for all number types/or use templates
struct Number: NumberBase{
union{int ival; float fval; double dval; ComplexNumber cmplx_val;}
NumberBase* num_t;
Set(int a)
{
ival=a;
//still kind of hack, hope it works because derived classes of Number dont add any fields
num_t = static_cast<NumberInt>(this);
}
}