posts - 28, comments - 179, trackbacks - 0, articles - 1
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

CEnumClass—类型安全的枚举类型

Posted on 2008-08-12 10:37 chemz 阅读(3124) 评论(3)  编辑 收藏 引用 所属分类: C++

                         CEnumClass—类型安全的枚举类型
    在前面的一篇文章《enum类型的本质》中非常详尽的讨论了C++中原生枚举类型的一些
本质特征(http://www.cppblog.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();
这种做法是显示的,你现在知道你自己在干什么,而不是编译器隐示为你完成的。

    对于其他剩余的内容,比如比较、输入输出等大家可以自行练习完成,这里就不论述了。
   

Feedback

# re: CEnumClass—类型安全的枚举类型  回复  更多评论   

2008-08-13 10:05 by Kevin Lynx
我觉得,用你这个类与普通的enum相比,更多时候我们需要的是一个方便的enum,即使它没有你这个class安全;
如果我没弄错的话,你这个类虽然sizeof为sizeof(int),但这并不是你所说的“同时也没有占用任何额外的空间”,因为还有很多static常量。

# re: CEnumClass—类型安全的枚举类型  回复  更多评论   

2010-05-12 22:53 by water
很棒啊,确实解决的非常彻底。

# re: CEnumClass—类型安全的枚举类型  回复  更多评论   

2011-02-22 11:42 by 路人
这样并不会提高程序的效率,反而会降低,影响程序的可读性,在枚举成员后面添加一个不使用的枚举值作为强制转化使用,如
enum TYPE
{
TYPE1 = 0,
TYPE2 = 0,
TYPE_INT = 0xffffffff, // 作为强制转化int类型使用
}

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理