union


有些类的实例,可能包含不同类型的成员,然而,在某个时间点上,只会有一个成员是有效的,例如,你可能会设计一个磁头类,磁头读取磁带中的数据并存储为对应的数据类型:

#include <iostream> 
using namespace std; 

class Output {
public:
    virtual void write(char cvalue) = 0;
    virtual void write(int ivalue) = 0;
    virtual void write(double dvalue) = 0;
    virtual ~Output() = default;
};

class Console : public Output {
public:
    void write(char cvalue) override {
        cout << cvalue << endl;
    }
    void write(int ivalue) override {
        cout << ivalue << endl;
    }
    void write(double dvalue) override {
        cout << dvalue << endl;
    }
};

class Head {
    char cvalue;
    int ivalue;
    double dvalue;

    enum {CHAR, INT, DOUBLE} type;

public:
    void read(char cvalue) {
        this->cvalue = cvalue;
        this->type = CHAR;
    }

    void read(int ivalue) {
        this->ivalue = ivalue;
        this->type = INT;
    }

    void read(double dvalue) {
        this->dvalue = dvalue;
        this->type = DOUBLE;
    }

    void writeTo(Output &output) {
        switch(this->type) {
            case CHAR:
                output.write(this->cvalue);
                break;
            case INT:
                output.write(this->ivalue);
                break;
            case DOUBLE:
                output.write(this->dvalue);
                break;
        }
    }
};

int main() { 
    Console console;
    Head head;

    head.read(10);
    head.writeTo(console);

    head.read('A');
    head.writeTo(console);

    return 0;
}

在上例中,Head一次只存储一种数据,并依type决定该写出哪种数据,因为Head一次只存储一种数据,不需要分别为cvalueivaluedvalue各开一个内存空间。

你可以使用union,它是一种特殊的类,维护足够的空间来置放多个数据成员中的一种,而不是为每个数据成员配置各自空间,例如:

...略
class Head {
    union {
        char cvalue;
        int ivalue;
        double dvalue;
    } value;

    enum {CHAR, INT, DOUBLE} type;

public:
    void read(char cvalue) {
        this->value.cvalue = cvalue;
        this->type = CHAR;
    }

    void read(int ivalue) {
        this->value.ivalue = ivalue;
        this->type = INT;
    }

    void read(double dvalue) {
        this->value.dvalue = dvalue;
        this->type = DOUBLE;
    }

    void writeTo(Output &output) {
        switch(this->type) {
            case CHAR:
                output.write(this->value.cvalue);
                break;
            case INT:
                output.write(this->value.ivalue);
                break;
            case DOUBLE:
                output.write(this->value.dvalue);
                break;
        }
    }
};
...略

Head中定义了匿名的union并创建了value成员,union配置足够大的空间以来容纳最大长度的数据成员,以上例而言,最大长度是double类型,因此value成员的大小是double的长度,由于union的数据成员共用内存空间,访问当前具有合法值的数据成员,才能正确地取数据,

union是种特殊的类,因此多数的类语法也可以用于union,例如,可以为union定义名称,默认权限为public,也可以定义为protectedprivate,可以定义构造函数、解构函数与成员函数等,然而不能拥有虚拟函数,不能继承其他类,也不能作为基类。

在 C++ 11 以后,成员的类型可以是自定义类型,可以有构造函数、解构函数或是复制指定运算符,不过并不建议,因为会令管理成员资源更为复杂。


展开阅读全文