C++ enum類型的一個更好的用法
enum 類型是c++的一個基本的類型,用於聲明可以枚舉的常量.相對於C#的enum, c++的enum有幾個缺陷:
1 不支持組合特性,也即FlagsAttribute屬性;
2 不支持toString方法,轉換爲字符串需要特別的函數實現;
3 不支持命名空間的特性.
前面的兩個比較明顯,我們只是討論第3個缺陷及其的一個彌補方法.
首先給出一段摘自MSDN的C#代碼:
public class EnumTest
{
enum Days {Sat=1, Sun, Mon, Tue, Wed, Thu, Fri};
static void Main()
{
int x = (int)Days.Sun;
int y = (int)Days.Fri;
Console.WriteLine("Sun = {0}", x);
Console.WriteLine("Fri = {0}", y);
}
}
代碼 1 C#使用枚舉
在上面的代碼中,枚舉類型Days不僅是一個類型,而且在使用當中還起到了命名空間的作用.
如果使用C++的代碼,應該是:
enum Days {Sat=1, Sun, Mon, Tue, Wed, Thu, Fri};
int main()
{
int x = Sun; //注意這裏!!
int y = Fri; //注意這裏!!
printf("Sun = {%d}", x);
printf ("Fri = {%d}", y);
return 0;
}
代碼 2 C++使用枚舉
在這裏,對enum類型,我們注意到C++和C#的兩個區別:
1 在C++中,enum向int的轉化是隱式進行的,不需要強制的類型轉換;
2 在C++中,使用枚舉類型不必帶有類型限定名,直接使用,類似於使用宏.
對於第一個區別,未必是一件壞事;但是對於第二個,則有明顯的問題.
我們列舉一個在c++中由於區別2而帶來問題的一個例子.假如我們聲明瞭另外的一個枚舉類型Planets: enum Planets {Moon, Earth, Sun }; 顯然,包含這個類型聲明的頭文件和代碼 2是不能在一個編譯單元中使用的,因爲Sun意義有分歧.這顯然是C++枚舉類型缺乏命名空間所帶來的後果;對C#則沒有這樣的問題.
當然,c++這樣設計也有一些好處,我們也使用一個例子說明:
class File
{
public:
enum OpenMode{ READ, WRITE};
void open( OpenMode , const char* filename );
};
int main()
{
File file;
file.open(OpenMode::READ,"c://1.txt");
return 0;
}
代碼 3 C++枚舉不使用限定名適合的例子
我們注意到,這裏的代碼可讀性非常好.但是這段代碼的特點是:枚舉類型嵌套的定義在父類型裏面.但是在很多的情況下,枚舉類型具有獨立的意義,不必嵌套在任何的類型裏面,例如上面的代碼 1.
要解決這個問題,傳統的做法有兩種:
1 仍然使用枚舉聲明,但是增加前綴,例如 enum Days{Day_Sat=1, Day_Sun, Day_Mon, Day_Tue, Day_Wed, Day_Thu, Day_Fri}; enum Planets{ Planet_Moon, Planet_Earth, Planet_Sun };
2 不再使用枚舉聲明,使用int替代,並且嵌套在類型之中,例如
struct Days
{
const static int Sat = 1;
const static int Sun = 2;
const static int Mon = 3;
const static int Tue = 4;
const static int Wed = 5;
const static int Thu = 6;
const static int Fri = 7;
};
struct Planets
{
const static int Moon = 0;
const static int Earth = 1;
const static int Sun = 1;
};
第一個方法顯得累贅,第二個方法則失去了枚舉類型的固有優點;我們希望提供一種把兩者結合起來的方法.
好了,囉嗦了這麼多,該拿出我們的乾貨了.下面是我們的方法:
namespace Days
{
enum Days_ {Sat=1, Sun, Mon, Tue, Wed, Thu, Fri};
};
typedef Days::Days_ Days;
int main()
{
Days d = Days::Sun;//1
int x = d;
printf("Sun = {%d}", x);
return 0;
}
代碼 4 C++ enum的用法
在代碼 4的1中,Days出現在兩次,第一次是用作類型,實際上指向Days::Days_,第二次是用作命名空間,指向命名空間Days.那麼這個魔法是怎麼實現的呢?顯然,編譯器提供了智能化,爲我們完成了這個工作.
枚舉類型Days_爲什麼要有一個下劃線? 我們的目的是提醒用戶不要使用Days::Days_,而是使用我們定義的類型別名Days.
這個方法稍微繁瑣一點,但是滿足了我們的要求:使用枚舉類型(帶來枚舉類型固有的優點);使得枚舉類型具有命名空間的特點(雖然起這個作用的並不是枚舉類型本身).