首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

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未定义的行为。许多编译器实现,作为一个非标准的语言扩展,阅读一个联盟的不活跃成员的能力。

二次

代码语言:javascript
复制
#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 <iostream> #include <string> #include <vector> union S { std::string str; std::vector<int> 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>)) 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<char>(); new (&s.vec) std::vector<int>; // now, s.vec is the active member of the union s.vec.push_back(10); std::cout << s.vec.size() << '\n'; s.vec.~vector<int>(); }

(since C++11)

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

成员寿命

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

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

二次

代码语言:javascript
复制
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。

二次

代码语言:javascript
复制
int main()
{
    union
    {
        int a;
        const char* p;
    };
    a = 1;
    p = "Jennifer";
}

二次

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

类似工会的课程

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

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

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

二次

代码语言:javascript
复制
#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 <variant> #include <iostream> int main() { std::variant<char, int, double> s = 'a'; std::visit({ std::cout << x << '\n';}, s); s = 123; std::visit({ std::cout << x << '\n';}, s); }

(since C++17)

缺陷报告

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

DR

Applied to

Behavior as published

Correct behavior

CWG 1940

c++14

anonymous unions only allowed non-static data members

static_assert also allowed

另见

c联合申报文件

*。

代码语言:txt
复制
 ? cppreference.com

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

扫码关注腾讯云开发者

领取腾讯云代金券

http://www.vxiaotou.com