type
status
date
slug
summary
tags
category
icon
password
Property
联合(
union
)是一种特殊类型的类。一个
union
可以有多个数据成员,但是在任意时刻只有一个数据成员可以有值。当给union
的某个成员赋值之后,该union
的其它成员就变成未定义的状态了。分配给一个union
对象的存储空间至少要能容纳它的最大的数据成员。union
需要的内存大小由最大的数据成员决定,内存大小将足够容纳这个数据类型。类的某些特性对
union
同样适用,但并非所有特性都如此:union
不能含有引用类型的成员,union
的成员可以是绝大多数类型。在C++11
标准中,含有构造函数或析构函数的类类型也可以作为union
的成员类型
union
可以为其成员指定public
、protected
、private
等标记。默认情况下union
的成员都是公有的
union
可以定义包括构造函数和析构函数在内的成员函数。但是由于union
既不能继承自其它类,也不能作为基类使用,所以在union
中不能含有虚函数
定义union
union
的定义以union
关键字开始,后跟随可选的名字,以及一系列在括号中的成员声明:使用union
类型
与内置类型一样,默认情况下
union
是不初始化的。用初始化聚合类一样的方法来初始化union
:如果提供了初始值,则该初始化被用于初始化第一个成员。因此,
first_token
的初始化过程实际上是给cval
成员赋了一个初值。可以通过成员访问运算符访问一个
union
对象的成员:赋值给
union
对象的数据成员将导致别的数据成员的内容是未定义的。因为
union
共用一个数据,因此当为一个数据赋值之后,就可以将所有的联合成员当做一个使用。但是使用的时候必须根据union
赋值的那个值的类型来进行使用匿名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个赋值运算符
- 下面是前三个赋值运算符的定义,其形式都是类似的:
- 如果为
union
的string
成员赋值,则与上面的运算符稍有不同:
拷贝控制函数(
copyUnion()
函数)、拷贝赋值运算符- 拷贝控制函数:
- 根据参数传入的
Token
对象,解析出其tok
,然后再进行分别的拷贝赋值 - 对于内置类型,直接赋值即可;对于
string
,采用定位new
的方式进行构造 - 先将拷贝当前类的判别式tok,然后再调用
copyUnion()
函数
- 赋值运算符的定义如下:
必须能处理
string
成员的三种可能情况:左侧运算对象和右侧运算对象都是stirng
;两个运算对象都不是string
;只有一个运算对象时string