联合和枚举

union

联合是一种特殊的struct,它的所有成员被分配在同一块内存区域中,因此联合实际占用的空间就是它最大的成员所占的空间. 自然在某个时刻,一个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 Value{
    Node* p;
    int i;
};

C++不会记录一个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的例子可改写为:

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 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!