🥥union:一种节省空间的类
2022-5-15
| 2023-8-2
0  |  阅读时长 0 分钟
type
status
date
slug
summary
tags
category
icon
password
Property

 
联合(union)是一种特殊类型的类。
一个union可以有多个数据成员,但是在任意时刻只有一个数据成员可以有值。当给union的某个成员赋值之后,该union的其它成员就变成未定义的状态了。分配给一个union对象的存储空间至少要能容纳它的最大的数据成员。union需要的内存大小由最大的数据成员决定,内存大小将足够容纳这个数据类型。
类的某些特性对union同样适用,但并非所有特性都如此:
  • union不能含有引用类型的成员,union的成员可以是绝大多数类型。在C++11标准中,含有构造函数或析构函数的类类型也可以作为union的成员类型
  • union可以为其成员指定publicprotectedprivate等标记。默认情况下union的成员都是公有的
  • union可以定义包括构造函数和析构函数在内的成员函数。但是由于union既不能继承自其它类,也不能作为基类使用,所以在union中不能含有虚函数
 

定义union

union的定义以union关键字开始,后跟随可选的名字,以及一系列在括号中的成员声明:
 

使用union类型

与内置类型一样,默认情况下union是不初始化的。用初始化聚合类一样的方法来初始化union
 
如果提供了初始值,则该初始化被用于初始化第一个成员。因此,first_token的初始化过程实际上是给cval成员赋了一个初值。
可以通过成员访问运算符访问一个union对象的成员:
赋值给union对象的数据成员将导致别的数据成员的内容是未定义的。
 
因为union共用一个数据,因此当为一个数据赋值之后,就可以将所有的联合成员当做一个使用。但是使用的时候必须根据union赋值的那个值的类型来进行使用
 
 
notion image
 
 
 

匿名union

匿名union是一个未命名的union,并且在右花括号和分号之间没有任何声明。一旦定义了一个匿名union,编译器就自动地为该union创建一个未命名的对象。
匿名union不能定义在全局作用域中,不能包含受保护的成员或私有成员,也不能定义成员函数。
 

含有类类型成员的union

C++早期版本中,union中不能含有定义了构造函数或拷贝控制成员的类类型成员。C++11标准取消了这一限制。如果union的成员类型定义了自己的构造函数/或拷贝控制成员,则该union的用法要比只含有内置类型成员的union复杂得多。
 
union的赋值与析构:
  • union包含的是内置类型的成员时:可以使用普通的赋值语句改变union保存的值
  • union含有特殊类类型成员时:将union的值改为类类型成员对应的值时,必须运行该类型的构造函数;如果将类类型成员的值改为另外的值时,必须运行该类型的析构函数
 
union的构造/拷贝:
  • 如果该类型自定义了默认构造函数或拷贝控制成员,则编译器将为union合成对应的版本并将其声明为删除的。例如一个union含有一个string类型的成员(string定义了5个拷贝控制成员以及一个默认构造函数,并且没有自定义默认构造函数或某个拷贝控制成员),编译器将合成缺少的成员并将其声明为删除的
  • 如果在某个类中含有一个union成员,而且该union含有删除的拷贝控制成员,则该类与之对应的拷贝控制操作也将是删除的
  • 当union包含的是内置类型的成员时:编译器按照成员的次序依次合成默认构造函数或拷贝控制成员
  • 当 union 内有类类型成员,并且其中有类类型成员定义了自己的默认构造函数或拷贝控制成员,union 合成的对应的成员就是被删除的。如果一个类的成员 union ,并且这个 union 有拷贝控制成员是被删除的,那么此类对应的拷贝控制成员也是被删除的。
 
 
使用类管理union成员
  • 对于union来说,想要构造或销毁类类型成员必须执行非常复杂的操作,因此通常把含有类类型成员的union内嵌在另一个类中。这个类可以管理并控制与union的类类型成员有关的状态转换
  • 例如:
    • union添加一个string成员,并将union定义为匿名的union,最后将它作为Token类的一个成员
    • 为了追踪union中到底存储了什么类型的值,我们通常会为union定义一个判别式。可以使用判别式辨认union存储的值。为了保持union与其判别式同步,将判别式也作为Token的成员(此处定义一个枚举类型作为判别式)
    • 在类中定义的函数包括默认构造函数、拷贝控制成员以及一组赋值运算符,这些赋值运算符可以将union的某种类型赋给union成员
类定义了:
  • 一个枚举,并将其作为tok成员的类型,我们使用tok作为判别式:当union存储的是一个int值时,tok的值为INT;当union存储的是一个string值时,tok的值为STR......以此类推
  • union含有一个析构函数:因为union可能存储string成员,因此如果union存储的是string,那么string的析构将被定义为删除的,因此需要手动的删除它
 
赋值运算符的定义
  • 在Token中定义了4个赋值运算符
  • 下面是前三个赋值运算符的定义,其形式都是类似的:
    • 如果为unionstring成员赋值,则与上面的运算符稍有不同:
       
      拷贝控制函数(copyUnion()函数)、拷贝赋值运算符
      • 拷贝控制函数:
        • 根据参数传入的Token对象,解析出其tok,然后再进行分别的拷贝赋值
        • 对于内置类型,直接赋值即可;对于string,采用定位new的方式进行构造
        • 先将拷贝当前类的判别式tok,然后再调用copyUnion()函数
      • 赋值运算符的定义如下:
        • 必须能处理string成员的三种可能情况:左侧运算对象和右侧运算对象都是stirng;两个运算对象都不是string;只有一个运算对象时string
           
    • C++
    • 嵌套类和局部类类成员指针
      目录