Posted on 2008-08-12 10:37
chemz 閱讀(3146)
評論(3) 編輯 收藏 引用 所屬分類:
C++
CEnumClass—類型安全的枚舉類型
在前面的一篇文章《enum類型的本質》中非常詳盡的討論了C++中原生枚舉類型的一些
本質特征(http://www.shnenglu.com/chemz/archive/2007/06/05/25578.html)。在文章的結
尾遺留了這樣一個話題:
由上面的說明枚舉類型有那么多的缺點,那我們怎樣才能夠有一個類型安全的枚舉類型呢?
同時也給出了解決這個問題的一個思想:
其實可以采用類類型來模擬枚舉類型的有限常量集合的概念,同時得到類型安全的好處。
沿著上面所闡述的思想來看為了解決這個問題必須通過C++中的類類型來強化類型的鑒別
能力,避免出現枚舉類型和默認的int的隱示自動轉換。我們來看看下面的實現:
template<typename SubT>
class CEnumClass
{
public:
friend bool operator==( const SubT &lhs, const SubT &rhs )
{
return lhs.value() == rhs.value();
}
friend bool operator!=( const SubT &lhs, const SubT &rhs )
{
return !( lhs == rhs );
}
int value() const { return m_value; }
protected:
CEnumClass( int i ) : m_value( i ) {}
CEnumClass( const CEnumClass &rhs ) : m_value( rhs.m_value ) {}
CEnumClass &operator=( const CEnumClass &rhs ) { m_value = rhs.m_value; return *this; }
protected:
int m_value;
};
首先簡單的說明一下這個類,CEnumClass是一個奇異遞歸模板,也就是說模板參數SubT
是CEnumClass<SubT>的子類,那么這樣一來為了聲明一個枚舉類就必須要想下面這樣:
EType.hpp
class EType : public CEnumClass<EType>
{
};
上面聲明就完成了enum EType這樣一個過程,但是一個枚舉類型不僅僅只是有類型,其中還
包括了有限常量枚舉子,那我們就需要在類聲明中添加對應的枚舉子的定義:
EType.hpp
class EType : public CEnumClass<EType>
{
public:
static const EType e1;
static const EType e2;
static const EType e3;
private:
EType( int i );
};
================================================================================
EType.cpp
const EType EType::e1 = 0;
const EType EType::e2 = 1;
const EType EType::e3 = 2;
EType::EType( int i ) : CEnumClass<EType>( i )
{
}
有了上面的定義就完成了一個枚舉類型的定義了,現在我們來分析一下這個類型是否真的能
夠解決文章《enum類型的本質》中所提到的所有缺陷和陷阱,同時又不失為真正的枚舉含義。
1. 有限常量集合
由于EType類的構造函數是私有的,所以無法在class聲明之外定義任何類的實例,所以
所有的類實例必須在class聲明中定義,有限性得到滿足。常量屬性可以通過是否能夠修改
實例的內容來進行判斷,這里沒有任何辦法可以修改枚舉子e1、e2、e3中的內容,因為他
們本身是const屬性,同時其成員均是外部不可訪問的。
2. 尺寸大小
分析一下這個類就可以很清楚的判斷出sizeof( EType ) == sizeof( int ),尺寸固定
成為一個int類型的大小,不再是可以隨著其取值范圍變化的了,同時也沒有占用任何額外
的空間,空間利用率非常高效。
3. 邊界約束
如果要定義一個枚舉類型的變量,就必須像下面這樣子:
EType val1 = EType::e1;
EType val2 = EType::e2;
EType val3 = EType::e3;
你不可能像下面這樣子:
EType val1;
EType val2 = 1;
EType val2 = 100;
也就是說一個枚舉變量的初始值必須在集合范圍之內,不可能越過這個范圍,也不可能取隨
機值。
4. 代替int類型
文章《enum類型的本質》中也明確的討論了enum類型不能在任何情況下替代int類型,而
在這里只要通過value函數調用就可以返回對應的int值,不就可以替代int類型了么。也就
是像這樣:
int i = val1.value();
這種做法是顯示的,你現在知道你自己在干什么,而不是編譯器隱示為你完成的。
對于其他剩余的內容,比如比較、輸入輸出等大家可以自行練習完成,這里就不論述了。