zoukankan      html  css  js  c++  java
  • [C++ primer]联合:节省空间的类

    联合是一种特殊的类。一个 union 对象可以有多个数据成员,但在任何时刻,只有一个成员可以有值。当将一个值赋给 union 对象的一个成员的时候,其他所有都变为未定义的。
    为 union 对象分配的存储的量至少与包含其最大数据成员的一样多。像任何类一样,一个 union 定义了一个新的类型。

    1、定义联合

    联合提供了便利的办法表示一组相互排斥的值,这些值可以是不同类型的。

    // objects of type TokenValue have a single member,
    // which could be of any of the listed types
    union TokenValue {
        char cval;
        int ival;
        double dval;
    };
    //sizeof(TokenValue)=sizeof(double)

    每个 union 对象的大小在编译时固定的:它至少与 union 的最大数据成员一样大。

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

    (联合里面的东西共享内存,所以静态、引用都不能用,因为他们不可能共享内存。)

    某些(但不是全部)类特征同样适用于 union。例如,像任何类一样,union可以指定保护标记使成员成为公用的、私有的或受保护的。默认情况下,union 表现得像 struct:除非另外指定,否则 union 的成员都为 public 成员。

    union 也可以定义成员函数,包括构造函数和析构函数。但是,union 不能作为基类使用,所以成员函数不能为虚数。
    union 不能具有静态数据成员或引用成员,而且,union 不能具有定义了构造函数、析构函数或赋值操作符的类类型的成员:

    union illegal_members {
        Screen s;           // error: has constructor
        static int is;      // error: static member
        int &rfi;           // error: reference member
        Screen *ps;         // ok: ordinary built-in pointer type
    };
    

     这个限制包括了具有带构造函数、析构函数或赋值操作符的成员的类。

    3、使用联合类型
    union 的名字是一个类型名:

    TokenValue first_token = {'a'};   // initialized TokenValue
    TokenValue last_token;            // uninitialized TokenValue object
    TokenValue *pt = new TokenValue;  // pointer to a TokenValue object
    

     像其他内置类型一样,默认情况下 union 对象是未初始化的。可以用与显式初始化简单类对象一样的方法显式初始化 union 对象。但是,只能为第一个成员提供初始化式。该初始化式必须括在一对花括号中。first_token 的初始化给它的 cval 成员一个值。

    4、使用联合的成员
    可以使用普通成员访问操作符(. 和 ->)访问 union 类型对象的成员:
    last_token.cval = 'z';
    pt->ival = 42;
    给 union 对象的某个数据成员一个值使得其他数据成员变为未定义的。使用 union 对象时,我们必须总是知道 union 对象中当前存储的是什么类型的值。通过错误的数据成员检索保存在 union 对象中的值,可能会导致程序崩溃或者其他不正确的程序行为。

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

    5、嵌套联合
    union 最经常用作嵌套类型,其中判别式是外围类的一个成员:

    class Token {
    public:
        // indicates which kind of value is in val
        enum TokenKind {INT, CHAR, DBL};
        TokenKind tok;
        union {           // unnamed union
        char cval;
        int ival;
        double dval;
        } val;            // member val is a union of the 3 listed types
    };
    

    这个类中,用枚举对象 tok 指出 val 成员中存储了哪种值,val 成员是一个(未命名的)union,它保存 char、int 或 double 值。
    经常使用 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 的成员的名字出现在外围作用域中。例如,使用匿名 union 重写的 Token 类如下:

    class Token {
    public:
        // indicates which kind of token value is in val
        enum TokenKind {INT, CHAR, DBL};
        TokenKind tok;
        union {              // anonymous union
            char cval;
            int ival;
            double dval;
        };
    };    
    

    因为匿名 union 不提供访问其成员的途径,所以将成员作为定义匿名union 的作用域的一部分直接访问。重写前面的 switch 以便使用类的匿名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 不能有私有成员或受保护成员,也不能定义成员函数。

    原文:C++primer(第四版)18.5节

  • 相关阅读:
    C# 数据为空,不能对NULL调用此方法或属性的解决办法
    Hadoop开启后jps显示只有jps
    Ubuntu中eclipse端口被占
    Ubuntu在终端执行命令时出现的错误
    sudo passwd root输入普通用户密码后显示用户不再sudoers文件中
    周总结(4.4)
    《构建之法》读后感(三)
    周总结(3.28)
    软件工程团队项目介绍
    解决phpstudy中nginx服务器运行项目报错404问题
  • 原文地址:https://www.cnblogs.com/kona/p/4659321.html
Copyright © 2011-2022 走看看