跳到主要内容

联合和枚举

union

联合是一种特殊的struct,它的所有成员被分配在同一块内存区域中,因此联合实际占用的空间就是它最大的成员所占的空间. 自然在某个时刻,一个union中只能保存一个成员的值.

union保存
enum Type {ptr,num}; // 一个Type可以保存值的ptr和num
struct Entry{
string name; // string是一个标准库类型
Type t;
Node* p;//如果t==ptr, 则使用ps
int i;//如果t==num,则使用i
};

void f(Entry* pe){
if(pe -> t == num){
cout << pe -> i;
}
};

因为p和i永远不会同时使用,所以浪费了内存空间.通过将两者定义为一个union成员,可以很容易的解决问题

union
union Value{
Node* p;
int i;
};

C++不会记录一个union保存了那种值,因此程序员必须自己做这个工作:

union和结构
struct Entry {
string name;
Type t;
Value v;
};

void f(Entry* entry){
if(pe->t == num)
cout << pe -> v.i;
}

维护类型域(type field,在本例中是t)与union中所存类型的对应关系很容易出错. 为了避免错误,我们可以强制这种对应关系:将联合和类型域分装在一个类中,只允许通过能正确使用联合的成员函数来访问他们. 在应用层面上,以来这种标记联合(tagged union)的抽象很常见也很有用. 我们应该尽量少的使用裸的union.

在大多数情况下我们可以使用标准库类型variant来避免直接使用union. 一个variant保存一组可选类型中一个类型的值. 例如一个variant<Node*,int>可以保存一个Node*或者一个int.

使用variant,Entry的例子可改写为:

variant
struct Entry {
string name;
variant<Node*,int> v;
};

void f(Entry* entry){
if(holds_alternative<int>(pe->v)) //*pe保存一个int吗
cout << get<int>(pe->v); //获取一个int
}

联合(union)是一种节省空间的特殊的类,一个 union 可以有多个数据成员,但是在任意时刻只有一个数据成员可以有值。当某个成员被赋值后其他成员变为未定义状态。联合有如下特点:

默认访问控制符为 public

可以含有构造函数、析构函数

不能含有引用类型的成员

不能继承自其他类,不能作为基类

不能含有虚函数

匿名 union 在定义所在作用域可直接访问 union 成员

匿名 union 不能包含 protected 成员或 private 成员

全局匿名联合必须是静态(static)的

#include<iostream>

union UnionTest {
UnionTest() : i(10) {};
int i;
double d;
};

static union {
int i;
double d;
};

int main() {
UnionTest u;

union {
int i;
double d;
};

std::cout << u.i << std::endl; // 输出 UnionTest 联合的 10

::i = 20;
std::cout << ::i << std::endl; // 输出全局静态匿名联合的 20

i = 30;
std::cout << i << std::endl; // 输出局部匿名联合的 30

return 0;
}

enum

备注

本文包含 ISO 标准 C++ 语言 enum 类型和 C++11 中引入的范围(或强类型)enum class 类型。 有关 C++/CLI 和 C++/CX 中 public enum class 或 private enum class 类型的详细信息,请参阅 enum class (C++/CLI and C++/CX)。

限定作用域的枚举类型

enum class open_modes { input, output, append };

不限定作用域的枚举类型

enum color { red, yellow, green };
enum { floatPrec = 6, doublePrec = 10 };

c++还提供了一种形式简单的自定义类型:enum

enum
enum class Color {red,blue,green,yellow};
enum class Traffic_light {green,yellow,red};

Color col = Color::red;
Traffic_light traffic = Traffic_light::red;

枚举值位于enum class的作用域之内, 因此我们可以在不同的enum class中重复使用这些枚举值而不至于引起混淆. 例如Color::red和Traffic_light::red显然不是一个东西

初始化和赋值
Color x = red; //wrong! which red?
Color y = Traffic_light::red; // wrong! this red is not that red;
Color z = Color::red; // correct!

int i = Color::red; // wrong!

Color c = 2; // wrong! 2 is not a Color
Color x = Color{5}; // correct! but a little verbose
Color y {6}; // correct!
Loading Comments...