结合C++11的新特性来解析C++中的枚举与联合

2020-01-06 14:21:27刘景俊


enum Suit { Diamonds = 5, Hearts, Clubs = 4, Spades };

Diamonds、Hearts、Clubs 和 Spades 的值分别是 5、6、4 和 5。请注意,5 使用了多次;尽管这并不符合预期,但是允许的。对于区分范围的枚举来说,这些规则是相同的。
强制转换规则
未区分范围的枚举常数可以隐式转换为 int,但是 int 不可以隐式转换为枚举值。下面的示例显示了如果尝试为 hand 分配一个不是 Suit 的值可能出现的情况:


int account_num = 135692;
Suit hand;
hand = account_num; // error C2440: '=' : cannot convert from 'int' to 'Suit'

将 int 转换为区分范围或未区分范围的枚举器时,需要强制转换。但是,你可以将区分范围的枚举器提升为整数值,而不进行强制转换。


int account_num = Hearts; //OK if Hearts is in a unscoped enum

按照这种方式使用隐式转换可能导致意外副作用。若要帮助消除与区分范围的枚举相关的编程错误,区分范围的枚举值必须是强类型值。区分范围的枚举器必须由枚举类型名称(标识符)限定,并且无法进行隐式转换,如以下示例所示:


namespace ScopedEnumConversions
{
  enum class Suit { Diamonds, Hearts, Clubs, Spades };

  void AttemptConversions()
  {
    Suit hand; 
    hand = Clubs; // error C2065: 'Clubs' : undeclared identifier
    hand = Suit::Clubs; //Correct.
    int account_num = 135692;
    hand = account_num; // error C2440: '=' : cannot convert from 'int' to 'Suit'
    hand = static_cast<Suit>(account_num); // OK, but probably a bug!!!

    account_num = Suit::Hearts; // error C2440: '=' : cannot convert from 'Suit' to 'int'
    account_num = static_cast<int>(Suit::Hearts); // OK
}

注意,hand = account_num; 行仍会导致对未区分范围的枚举发生的错误,如前面所示。它可以与显式强制转换一起使用。但是,借助区分范围的枚举,不再允许在没有显式强制转换的情况下在下一条语句 account_num = Suit::Hearts; 中尝试转换。

联合

union 是用户定义的类型,其中所有成员都共享同一个内存位置。 这意味着在任何给定时间,联合都不能包含来自其成员列表的多个对象。 这还意味着无论联合具有多少成员,它始终仅使用足以存储最大成员的内存。
具有大量对象和/或内存有限时,联合可用于节省内存。 但是,需要格外小心才能正确使用它们,因为由你负责确保可始终访问写入的最后一个成员。 如果任何成员类型具有不常用构造函数,则必须编写附加代码来显式构造和销毁该成员。 使用联合之前,应考虑是否可以使用基类和派生类来更好地表示尝试解决的问题。