C++ Primer 5th笔记(chap 19 特殊工具与技术)union

Posted thefist11

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ Primer 5th笔记(chap 19 特殊工具与技术)union相关的知识,希望对你有一定的参考价值。

1. 定义

联合( union) 是一种特殊的类。 一个 union 可以有多个数据成员, 但是在任意时刻的某个成员赋值之后, 该 union 的其他成员就变成未定义的状态了。

  • 对象的存储空间至少要能容纳它的最大的只有一个数据成员可以有值。
  • union 既不能继承自其他类, 也不能作为基类使用
  • 可用来表示一组类型不同的互斥值
// Token 类型的对象只有一个成员, 该成员的类型可能是下列类型中的任意一种
union Token {
	// 默认情况下成员是公有的
	char cval;
	int ival;
	double dval;
}

Token first_token = {'a'};      // 初始化cval成员, 如果提供初始值则用于初始化第一个成员
Token last_token;               // 未初始化的Token对象
Token *pt = new Token;          // 指向一个未初始化的Token对象的指针

//使用 union 类型
last_token.cval = 'z';
pt->ival = 42;

1.1 匿名 union( anonymous union)

一个未命名的 union, 并且在右花括号和分号之间没有任何声明

union {
    char cval;
    int ival;
    double dval;
};  // 未命名对象, 我们可以直接访问它的成员
cval = 'a';    // 为匿名union赋一个新值
ival = 42;     // 该对象当前保存的值是42
  • 在匿名 union 的定义所在的作用域内该 union 的成员都是可以直接访问的
  • 不能包含受保护的成员或私有成员, 也不能定义成员函数

1.2 内置类型

当 union包含的是内置类型的成员时, 编译器将按照成员的次序依次合成默认构造函数或拷贝控制成员。 但是如果union 含有类类型的成员,并且该类型自定义了默认构函数或拷贝控制成员, 则编译器将为union合成对应的版本并将其声明为删除的。

eg. string 类定义了五个拷贝控制成员以及一个默认构造函数。 如果有 string 类型的成员, 并且没有自定义默认构造函数或某个拷贝控制成员, 则编译器将合成缺少的成员并将其声明成删除的。 如果在某个类中含有一个含有删除的拷贝控制成员, 则该类与之对应的拷贝控制操作也将是删除的。

1.3 使用类管理 union 成员

通常会定义一个独立的对象, 该对象称为称为union的判别式 (discriminant)

eg. 使用 tok 作为判别式。 当 union 存储的是一个 int 值时, tok 的值是 INT: 当union 存储的是一个 string 值时, tok 的值是 STR: 以此类推

class Token {
public:
    //因为union含有一个string成员,所以Token必须定义拷贝控制成员
    //定义移动构造函数和移动赋值运算符的任务
    Token() :tok(INT), ival{ 0 }{ }
    Token(const Token& t) :tok(t.tok) { copyUnion(t); }
    Token& operator=(const Token&);

    //如果union含有一个string成员,则我们必须销毁它
    ~Token() { if (tok == STR) sval.~string(); }
    Token& operator=(const string&);
    Token& operator=(int);
    Token& operator=(double);
    Token& operator=(char);

private:
    enum {INT,CHAR,DBL,STR} tok;                    //判别式
    union {//匿名union
        char        cval;
        int           ival;
        double    dval;
        string      sval;
    };//每个Token对象含有一个该未命名union类型的未命名成员

    //检查判别式,然后酌情拷贝union成员
    void copyUnion(const Token&);
};

Token& Token::operator=(const string& s)
{
    if (tok == STR)
        sval = s;
    else
        new(&sval) string(s);
    tok = STR;
    return *this;
}

Token& Token::operator=(int i)
{
    if (tok == STR) sval.~string();
    tok = INT;
    ival = i;
    return *this;
}

Token& Token::operator=(double d)
{
    if (tok == STR) sval.~string();
    tok = DBL;
    dval = d;
    return *this;
}

Token& Token::operator=(char c)
{
    if (tok == STR) sval.~string();
    tok = CHAR;
    cval = c;
    return *this;
}

//管理需要拷贝控制的联合成员
void Token::copyUnion(const Token&  t)
{
    switch (t.tok) {
    case INT:ival = t.ival; break;
    case STR:new(&sval) string(t.sval); break;
    case CHAR:cval = t.cval; break;
    case DBL:dval = t.dval; break;
    }
}

 Token& Token::operator=(const Token& t)
{
    //如果此对象的值是string而t的值不是,而我们必须释放原来的string
    if (tok == STR && t.tok != STR)  sval.~string();
    if (tok == STR && t.tok == STR)
        sval = t.sval;
    else
        copyUnion(t);
    tok = t.tok;
    return *this;
}

以上是关于C++ Primer 5th笔记(chap 19 特殊工具与技术)union的主要内容,如果未能解决你的问题,请参考以下文章

C++ Primer 5th笔记(chap 19 特殊工具与技术)malloc 函数与 free 函数

C++ Primer 5th笔记(chap 19 特殊工具与技术)控制内存分配

C++ Primer 5th笔记(chap 19 特殊工具与技术)使用 RTTI

C++ Primer 5th笔记(chap 19 特殊工具与技术)typeid

C++ Primer 5th笔记(chap 19 特殊工具与技术)定位 new 表达式

C++ Primer 5th笔记(chap 19 特殊工具与技术)成员函数指针