19.6 union一种节省空间的类--使用类管理union成员

来源:互联网 发布:java 未来前景 编辑:程序博客网 时间:2024/06/05 01:19

含有类类型成员的union:

c++早期版本规定,在union中不能含有定义了构造函数或拷贝控制成员的类类型成员。


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

所以需要使用类来管理union成员


class Token
{
public:
    //因为union 含有一个string成员,所以Token必须定义拷贝控制成员
    Token():tok(INT), ival(0){}
    Token(const Token &t):tok(t.tok)
    { copyUnion(t);qDebug() << "....value constructer";}
    Token(Token&&t) noexcept:tok(t.tok)
    { copyUnion(t);qDebug() << "....move constrrcter";}
    Token &operator =(Token &&rhs) noexcept
    {
        if ( this != &rhs )
        {
            if ( STR == tok && STR != rhs.tok )
            {
                sval.~string();
            }
            if ( STR == tok && STR == rhs.tok)
            {
                sval = rhs.sval;
            }
            else
            {
                copyUnion(rhs);
            }
        }
        qDebug() << ".....move operator=";
        return *this;
    }
    Token &operator=(const Token &rhs)
    {
        if ( this != &rhs )
        {
            if ( STR == tok && STR != rhs.tok )
            {
                sval.~string();
            }
            if ( STR == tok && STR == rhs.tok)
            {
                sval = rhs.sval;
            }
            else
            {
                copyUnion(rhs);
            }
        }
        qDebug() << ".....value opeartor=";
        return *this;
    }
    //如果union含有一个string成员,则我们必须销毁它,(调用析构函数会销毁对象,但是不会释放内存,如果需要的话,可以重新使用该空间)
    //因为析构函数不清楚union存储的值是什么类型,所以它无法确定应该销毁那个成员
    ~Token() { if (STR == tok) sval.~string(); }
    //下面的赋值运算符负责设置union的不同成员
    Token &operator =(const std::string &s)
    {
        if ( STR == tok )
        {
            sval = s;
        }
        else
        {
            new (&sval) string(s);
        }
        tok = STR;
        return *this;
    }
    Token &operator =(char c)
    {
        if ( STR == tok )
        {
            sval.~string();
        }
        cval = c;
        tok = CHAR;
        return *this;
    }
    Token &operator =(int i)
    {
        if (STR == tok )
        {
            sval.~string();
        }
        ival = i;
        tok = INT;
        return *this;
    }
    Token &operator =(double d)
    {
        if ( STR == tok )
        {
            sval.~string();
        }
        dval = d;
        tok = DBL;
        return *this;
    }
private:
    enum { INT, CHAR, DBL, STR } tok;//判别式
    union {//匿名 union
        char cval;
        int  ival;
        double dval;
        std::string sval;
    };//每个Token对象含有一个改未命名union类型的未命名成员
    //检查判别式,然后酌情拷贝union成员
    void copyUnion(const Token&rhs)
    {
        switch (rhs.tok) {
        case INT:
            ival = rhs.ival;
            break;
        case DBL:
            dval = rhs.dval;
            break;
        case CHAR:
            cval = rhs.cval;
            break;
        case STR:
            new (&sval) string(rhs.sval);
            break;
        default:
            break;
        }
    }
};

union类(联合)硬性知识

union不能含有引用类型的成员,在c++新标准中, 含有构造函数或析构函数的类类型也可以作为union的成员类型。union可以为其成员指定public, protected和private保护标记,默认是共有的。union可以定义包含构造函数和析构函数在内的成员函数。但是不能继承也不能被继承,所以union不能含有虚函数。


匿名的union:

不能标记protected, private,也不能定义成员函数。

原创粉丝点击