在线文档教程
C++
语言 | Language

Union declaration

联合声明

联合是一种特殊的类类型,只能容纳它的非静态类之一。数据成员一次。

联合声明的类说明符类似于类或结构声明:

union attr class-head-name { member-specification }

attr(C++11)-optional sequence of any number of attributes
class-head-name-the name of the union that's being defined. Optionally prepended by nested-name-specifier (sequence of names and scope-resolution operators, ending with scope-resolution operator). The name may be omitted, in which case the union is unnamed
member-specification-list of access specifiers, member object and member function declarations and definitions.

联合可以有成员函数%28,包括构造函数和析构函数%29,但不具有虚拟函数。

联合不能有基类,也不能用作基类。

联合不能有引用类型的数据成员。

Unions cannot contain a non-static data member with a non-trivial special member function (copy constructor, copy-assignment operator, or destructor).(until C++11)
If a union contains a non-static data member with a non-trivial copy/move constructor, copy/move assignment, or destructor), that function is deleted by default in the union and needs to be defined explicitly by the programmer. If a union contains a non-static data member with a non-trivial default constructor, the default constructor of the union is deleted by default unless a variant member of the union has a default member initializer. At most one variant member can have a default member initializer.(since C++11)

就像在结构声明中,联合中的默认成员访问权限为公众...

解释

工会的规模仅限于其最大的数据成员。其他数据成员作为该最大成员的一部分以相同的字节分配。该分配的详细信息是实现定义的,它是从最近编写的%27T的工会成员中读取的%27s未定义的行为。许多编译器实现,作为一个非标准的语言扩展,阅读一个联盟的不活跃成员的能力。

二次

#include <iostream> union S { std::int32_t n; // occupies 4 bytes std::uint16_t s[2]; // occupies 4 bytes std::uint8_t c; // occupies 1 byte }; // the whole union occupies 4 bytes int main() { S s = {0x12345678}; // initializes the first member, s.n is now the active member // at this point, reading from s.s or s.c is undefined behavior std::cout << std::hex << "s.n = " << s.n << '\n'; s.s[0] = 0x0011; // s.s is now the active member // at this point, reading from n or c is UB but most compilers define it std::cout << "s.c is now " << +s.c << '\n' // 11 or 00, depending on platform << "s.n is now " << s.n << '\n'; // 12340011 or 00115678 }

二次

每个成员都被分配,就好像它是类的唯一成员一样。

If members of a union are classes with user-defined constructors and destructors, to switch the active member, explicit destructor and placement new are generally needed: #include #include #include union S { std::string str; std::vector vec; ~S() {} // needs to know which member is active, only possible in union-like class }; // the whole union occupies max(sizeof(string), sizeof(vector)) int main() { S s = {"Hello, world"}; // at this point, reading from s.vec is undefined behavior std::cout << "s.str = " << s.str << '\n'; s.str.~basic_string( new (&s.vec) std::vector; // now, s.vec is the active member of the union s.vec.push_back(10 std::cout << s.vec.size() << '\n'; s.vec.~vector( }(since C++11)

如果两个联合成员都是标准布局类型,那么它将定义为%27s,以检查它们在任何编译器上的公共子序列。

成员寿命

大寿命工会成员的活动开始。如果另一个成员以前是活动的,它的生命周期就结束了。

当联合的活动成员被表单的赋值表达式切换时E1 = E2的成员访问和数组下标子表达式中出现的每个联合成员X使用内置赋值运算符或普通赋值运算符。E1这不是一个具有非平凡或删除的默认构造函数的类,如果对X的修改在类型混叠规则下有未定义的行为,则在指定的存储中隐式创建X类型的对象;不执行初始化,并在左、右操作数的值计算之后和赋值之前对其生命周期的开始进行排序。

二次

union A { int x; int y[4]; }; struct B { A a; }; union C { B b; int k; }; int f() { C c; // does not start lifetime of any union member c.b.a.y[3] = 4; // OK: "c.b.a.y[3]", names union members c.b and c.b.a.y; // This creates objects to hold union members c.b and c.b.a.y return c.b.a.y[3]; // OK: c.b.a.y refers to newly created object } struct X { const int a; int b; }; union Y { X x; int k; }; void g() { Y y = { { 1, 2 } }; // OK, y.x is active union member (9.2) int n = y.x.a; y.k = 4; // OK: ends lifetime of y.x, y.k is active member of union y.x.b = n; // undefined behavior: y.x.b modified outside its lifetime, // "y.x.b" names y.x, but X's default constructor is deleted, // so union member y.x's lifetime does not implicitly start }

二次

匿名工会

匿名联盟是一个未命名的联合定义,它不同时定义任何变量%28,包括联合类型的对象、引用或指向联合%29的指针。

union { member-specification } ;

匿名联合还有进一步的限制:它们不能有成员函数,不能有静态数据成员,而且它们的所有数据成员都必须是公共的。唯一允许的声明是非静态数据成员和静态[医]断言声明%28自C++14%29。

匿名工会的成员被注入到封闭的范围%28中,并且不能与在其中声明的其他名称冲突%29。

二次

int main() { union { int a; const char* p; }; a = 1; p = "Jennifer"; }

二次

命名空间范围的匿名联合必须声明为静态的,除非它们出现在未命名的命名空间中。

类似工会的课程

工会式课程是至少有一个匿名工会作为成员的%28非工会%29类或工会。类似联盟的类有一组变式成员*

  • 其成员匿名联盟的非静态数据成员;

  • 此外,如果类似工会的类是一个联盟,那么它的非静态数据成员就不是匿名联合。

类类可用于实现标记工会...

二次

#include <iostream> // S has one non-static data member (tag), three enumerator members (CHAR, INT, DOUBLE), // and three variant members (c, i, d) struct S { enum{CHAR, INT, DOUBLE} tag; union { char c; int i; double d; }; }; void print_s(const S& s) { switch(s.tag) { case S::CHAR: std::cout << s.c << '\n'; break; case S::INT: std::cout << s.i << '\n'; break; case S::DOUBLE: std::cout << s.d << '\n'; break; } } int main() { S s = {S::CHAR, 'a'}; print_s(s s.tag = S::INT; s.i = 123; print_s(s }

二次

The C++ standard library includes std::variant, which can replace many uses of unions and union-like classes. The example above can be re-written as. #include #include int main() { std::variant s = 'a'; std::visit{ std::cout << x << '\n';}, s s = 123; std::visit{ std::cout << x << '\n';}, s }(since C++17)

缺陷报告

以下行为更改缺陷报告追溯应用于先前发布的C++标准。

DRApplied toBehavior as publishedCorrect behavior
CWG 1940c++14anonymous unions only allowed non-static data membersstatic_assert also allowed

另见

c联合申报文件

*。

© cppreference.com

在CreativeCommonsAttribution下授权-ShareAlike未移植许可v3.0。

http://en.cppreference.com/w/cpp/language/Union