union学习

发布时间 2023-10-03 16:24:23作者: hacker_dvd
#include <iostream>
#include <string>

class Token {
public:
  Token() : tok(INT), ival(0) {}
  ~Token() {
    if (tok == STR) {
      sval.~basic_string();  // 联合体中编译器不会自动调用析构函数
    }
  }

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

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

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

  Token& operator=(const std::string& s) {
    if (tok == STR) {
      sval = s;
    }
    else {
      // 定位 new,在已经分配的内存位置上构造一个对象,而不是在堆上分配新的内存
      // 在 sval 的当前位置上构造一个新的 std::string 对象,并使用 s 来初始化它
      new(&sval) std::string(s);
    }
    tok = STR;
    return *this;
  }

  // 赋值运算符(为已存在的对象赋值时被调用)
  Token& operator=(const Token& t) {
    if (tok == STR && t.tok != STR) {
      sval.~basic_string();
    }
    if (tok == STR && t.tok == STR) {
      sval = t.sval;
    }
    else {
      copyUnion(t);
    }
    tok = t.tok;
    return *this;
  }

private:
  enum {INT, CHAR, DBL, STR} tok;
  union {
    char cval;
    int ival;
    double dval;
    std::string sval;
  };
  void copyUnion(const Token& t) {
    switch (t.tok)
    {
    case INT:
      ival = t.ival; break;
    case CHAR:
      cval = t.cval; break;
    case DBL:
      dval = t.dval; break;
    case STR:
      new(&sval) std::string(t.sval); break;
    }
  }
};

int main() {
  // 创建 Token 对象
  Token t1, t2, t3, t4, t5;

  // 使用赋值运算符为对象赋值
  t1 = 42;               // int
  t2 = 'a';             // char
  t3 = 3.14;            // double
  t4 = std::string("Hello, World!");  // std::string

  // 输出结果
  std::cout << "t1 assigned with int: 42" << std::endl;
  std::cout << "t2 assigned with char: 'a'" << std::endl;
  std::cout << "t3 assigned with double: 3.14" << std::endl;
  std::cout << "t4 assigned with string: \"Hello, World!\"" << std::endl;

  // 使用拷贝赋值运算符
  t5 = t4;
  std::cout << "t5 copied from t4 (which contains a string)" << std::endl;

  // 为已包含字符串的 Token 对象赋值一个 int
  t4 = 100;
  std::cout << "t4 reassigned with int: 100" << std::endl;

  return 0;
}