首页 > 代码库 > C++ Primer 学习笔记_105_特殊工具与技术 --联合:节省空间的类

C++ Primer 学习笔记_105_特殊工具与技术 --联合:节省空间的类

特殊工具与技术

--联合:节省空间的类

联合是一种特殊的类。一个 union 对象可以有多个数据成员,但在任何时刻,只有一个成员可以有值当将一个值赋给 union 对象的一个成员的时候,其他所有都变为未定义的。 

为 union 对象分配的存储的量至少与包含其最大数据成员的一样多。联合提供了便利的办法表示一组相互排斥的值,这些值可以是不同类型的。

 

1.定义联合

作为例子,我们可能有一个处理不同各类数值或字符数据的过程。该过程可以定义一个 union 来保存这些值:

union ToKenValue
{
    char cval;
    int ival;
    double dval;
};

 

2.没有静态数据成员,引用成员或类数据成员

union可以指定保护标记使成员成为公用的,私有的或受保护的。 默认情况下, union 表现得像 struct:除非另外指定,否则 union 的成员都为 public 成员.

union 可以定义成员函数,包括构造函数析构函数。但是,union 不能作为基类使用,所以成员函数不能为虚函数。 

union 不能具有静态数据成员或引用成员,而且,union 不能具有定义了构造函数、析构函数或赋值操作符的类类型的成员:

union illegal_memgers
{
    Screen s;
    static int is;
    int &rfi;
    Screen *ps;
};

 

3.使用联合类型

Union的名字是一个类型名:

    ToKenValue first_token = {‘a‘};
    ToKenValue last_token;
    ToKenValue *pt = new ToKenValue;


说明:可以用与显式初始化简单类对象一样的方法显式初始化 union 对象。但是,只能为第一个成员提供初始化式。该初始化式必须括在一对花括号中。first_token 的初始化给它的 cval 成员一个值。

 

4.使用联合的成员

可以使用普通成员访问操作符(和 ->)访问 union 类型对象的成员:

    last_token.cval = ‘z‘;
    pt -> ival = 43; 

给 union 对象的某个数据成员一个值使得其他数据成员变为未定义的。使用 union 对象时,我们必须总是知道 union 对象中当前存储的是什么类型的值。通过错误的数据成员检索保存在 union 对象中的值,可能会导致程序崩溃或者其他不正确的程序行为。 

[实践]

避免通过错误成员访问 union 值的最佳办法是,定义一个单独的对象跟踪 union 中存储了什么值。这个附加对象称为 union 的判别式。

 

5.嵌套联合

Union最经常用做嵌套类型,其中判别式是外围类的一个成员:

class Token
{
public:
    enum TokenKind {INT,CHAR,DBL};
    TokenKind tok;
    union
    {
        char   cval;
        int    ival;
        double dval;
    } val;
};

[说明]枚举对象tok指出val成员中存储了那种值.

 

经常使用switch测试判别式,然后根据union中当前存储的值进行处理:

    Token token;
    switch (token.tok)
    {
    case Token::INT:
        token.val.ival = 42;
        break;
    case Token::CHAR:
        token.val.cval = ‘a‘;
        break;
    case Token::DBL:
        token.val.dval = 3.14;
        break;
    }

 

6.匿名联合

不用于定义对象的未命名 union 称为匿名联合。匿名 union 的成员的名字出现在外围作用域中

class Token
{
public:
    enum TokenKind {INT,CHAR,DBL};
    TokenKind tok;
    union
    {
        char   cval;
        int    ival;
        double dval;
    };
};

 

因为匿名union不提供访问其成员的途径,以将成员作为定义匿名union的作用域的一部分直接访问.

    Token token;
    switch (token.tok)
    {
    case Token::INT:
        token.ival = 42;
        break;
    case Token::CHAR:
        token.cval = ‘a‘;
        break;
    case Token::DBL:
        token.dval = 3.14;
        break;
    }

匿名union不能有私有成员或受保护成员(要不然怎么访问^~^),也不能定义成员函数.