`
yidongkaifa
  • 浏览: 4059658 次
文章分类
社区版块
存档分类
最新评论

C++枚举类型讨论

 
阅读更多
Technorati 标签: C++,enum

枚举类型enum,即enumeration的前四个字母,从字面上就可以看是它定义的值就是某一种值的穷举,例如一年中的12个月,一周中的七天、性别等。假设在一个应用程序中要实现几种数据传输方式,协议可能支持HTTP、FTP几种:

enum TransProtocol{

HTTP = 0,

FTP

};

TransProtocol prot = HTTP;

switch(prot){

case HTTP:

......

break;

case FTP:

......;

break;

default: ......

}

在C++98中enum变量的实际大小由编译器决定,只要能够保存enum的成员即可,而在将要发布的新的C++0x中,可以指定enum的实际实现类型,如实现为int类型。

enum Month : int { Jan, Feb, …, Dec }

其实,enum的作用就是定义一些整数型的常量,其数值默认从0开始,下面的值依次加1;而且在定义时可以为每一个常量定义一个特殊的值,而不仅限于用默认值,如[??],如果前面定义了特殊值,后面的将会依次在此值上递增。例如[??]中,如果Hide没有指定0x04,其值将会是0x03。

enum FileAttribute {

Read = 0x01,

Write = 0x02,

Hide = 0x04,

System = 0x08

};

用枚举值定义常量不仅可以像宏那样提高程序的可读性,而且还具有像用const定义的常量一样具备强类型检查。此外,在遍历一组值时,使用枚举就比使用常量方便得多,如[??]。以后如果支持了新的传输协议,只需要在PROTOCOL_COUNT增加一个变量即可,而后面用于遍历的for循环代码无需修改,使程序具有较好的扩展性,便于维护与升级,这也是一个在C/C++中惯用的技巧。

enum TransProtocol{ HTTP = 0, FTP, PROTOCOL_COUNT};

int main( void )

{

for(int p= 0; p < PROTOCOL_COUNT; ++p){

cout<<"Protocol:"<

}

return 0;

}

1.1.1. 枚举类型的作用域

在C++中使用枚举类型不需要像C#中那样需要类型名作为标识符的一部分,如HTTP在C#中需要用TransProtocol::HTTP。这样在大型项目中将可能会出现命名冲突的问题,通常主要有几种解决方法。

1) 加前缀。例如,为TransProtocol的第一个成员都增加一个前缀ETP_,即:

enum TransProtocol { ETP_HTTP, ETP_FTP };

2) 使用命名空间,例如

namespace TransProtocol { enum TransProtocol { HTTP, FTP }; }

这样,在用到HTTP或FTP时就需要在前面加上域标识符TransProtocol::HTTP。

3) 将enum定义为类的嵌套类型,如[??]。

class DataTransfer

{

public:

enum TransProtocol { HTTP, FTP };

......

};

DataTransfer::TransProtocol prot = DataTransfer::HTTP;

其实,后两种方案用法基本相同,可以根据引用所定义枚举的范围选择使用,不推荐使用第1种方法。

1.1.2. 枚举值的范围

虽然使用枚举比使用宏和常量都有优点,但还有一个问题,那就是每次将整数强制转换为枚举类型之前,客户端代码都必须检查枚举值范围的合法性,否则软件就可能存在未知的BUG。

enum Weekday { Sun, Mon, Tue, Wed, Thu, Fri, Sat };

void PrintWeekday(Weekday day) { … }

int main( void )

{

PrintWeekday((Weekday)8); // 潜在BUG

}

要保证传给PrintWeekday的实参合法,则必须在PrintWeekday函数中对参数进行检验,如果有另外一个函数也使用了Weekday,则也需要实现对参数值的检验,这样程序里将可能出向很多重复代码,难以维护。

1.1.3. 使用枚举类

除了上节中谈到枚举类型由于取值范围问题,可能使客户端代码存在不安全隐患;我们也不能像在C#或Java那样每个枚举变量都是一个对象,都有一个从object类继承而来的ToString方法,把对象转换为可以打印的字符串便于调试。而枚举值在C++中只是一种POD类型,其实质与int类型并无本质区别,不同于类类型,没有成员函数,故而不可能具有ToString方法,如果我们想实现:

std::cout<

则也必须将HTTP实现为某个类的实例,下面定义一个枚举类的实例。

#include

#include

#include

using namespace std;

class ScriptLanguage

{

public:

static const ScriptLanguage Shell;

static const ScriptLanguage Lua;

static const ScriptLanguage Python;

static const ScriptLanguage Perl;

inline const string& ToString( void ) const

{ return _langNames[_langId]; }

inline int Id( void ) const { return (int)_langId; }

inline bool operator==(const ScriptLanguage& other) const

{ return _langId == other._langId; }

inline bool operator!=(const ScriptLanguage& other) const

{ return _langId != other._langId; }

inline operator int( ) const { return _langId; }

inline operator string( ) const

{ return _langNames[_langId]; }

static ScriptLanguage FromString( const string& name);

public:

enum _ScriptLanguageEnum{

EShell , ELua, EPython, EPerl,

EScriptLanguageCount

};

explicit ScriptLanguage( const _ScriptLanguageEnum langId );

private:

_ScriptLanguageEnum _langId;

static const string _langNames[];

};

const string ScriptLanguage::_langNames[]

= {"shell", "lua", "python", "perl"};

const ScriptLanguage ScriptLanguage::Shell(ScriptLanguage::EShell);

const ScriptLanguage ScriptLanguage::Lua(ScriptLanguage::ELua);

const ScriptLanguage ScriptLanguage::Python(ScriptLanguage::EPython);

const ScriptLanguage ScriptLanguage::Perl(ScriptLanguage::EPerl);

ScriptLanguage ScriptLanguage::FromString( const string& name )

{

for(int i=0; i

if(name == _langNames[i]){

return ScriptLanguage((_ScriptLanguageEnum)i);

}

}

throw std::invalid_argument("Invalid ScriptLanguage name:" + name);

}

ScriptLanguage::ScriptLanguage( const _ScriptLanguageEnum langId ) :_langId(langId)

{

}

// 测试代码

int main( void )

{

ScriptLanguage shell = ScriptLanguage::Shell;

ScriptLanguage lua = ScriptLanguage::Lua;

ScriptLanguage python=ScriptLanguage::FromString("python");

ScriptLanguage perl = ScriptLanguage::FromString("perl");

assert(shell != lua && shell != python && python != perl);

assert(shell==ScriptLanguage::Shell

&&lua== ScriptLanguage::Lua);

assert(shell.ToString()==ScriptLanguage::Shell.ToString());

assert((int)shell==shell.Id());

assert( (string)lua == ScriptLanguage::Lua.ToString() );

assert( (string)lua == "lua");

switch(shell){

case ScriptLanguage::EShell: // do something

break;

case ScriptLanguage::ELua: // do something

break;

default: // do something

break;

}

return 0;

}

在实现枚举类时使用了一些C++的特性:

l 虽然使用类封装了_ScriptLanguageEnum,但其效率并不比直接使用枚举类型低多少,因为数据成员也只有一个枚举型的成员变量;

l ToString方法直接返回的是静态变量的引用,虽然是函数,但通过inline关键字标识,编译器可以很容易地优化为对数组的直接引用,并没有函数调用对效率的影响,而且这些常量的构造是在main函数执行前已经初始化完毕了;

l 通过对类型转换函数的定义,可以方便地将 ScriptLanguage类型转换为string类型或int类型,使用起来非常方便;并且通过对int类型转换函数的定义,使得ScriptLanguage类型变量可以直接用于switch语句,而不必使用多个if-else分支语句。

l 将构造函数定义为private,保证了客户端代码不会使用非常的int型类型强制转换为ScriptLanguage类型,这比使用enum类型更为安全。

通过使用类替代枚举类型,基本模拟了C#中的枚举类型,增加了ToString函数和FromString函数,方便用于人机界面,而且并没有对应用程序的性能有明显影响(虽然静态变量多占用了一点内存)。

分享到:
评论

相关推荐

    深入理解C++11:C++11新特性解析与应用

    1555.1 强类型枚举 1555.1.1 枚举:分门别类与数值的名字 1555.1.2 有缺陷的枚举类型 1565.1.3 强类型枚举以及C++11对原有枚举类型的扩展 1605.2 堆内存管理:智能指针与垃圾回收 1635.2.1 显式内存管理 1635.2.2 ...

    c++教案 ==========

    6.7 结构类型、枚举类型、类型别名· 30 6.7.1结构类型· 30 6.7.2枚举类型· 30 第七章 继承机制· 30 7.1 继承的基本概念· 30 7.1.1 IS-A关系· 30 7.1.2 继承机制· 31 7.1.3 继承的作用· ...

    谭浩强C语言程序设计,C++程序设计,严蔚敏数据结构,高一凡数据结构算法分析与实现.rar

    11.10.1 枚举类型的定义和枚举变量的说明 184 11.10.2 枚举类型变量的赋值和使用 185 11.11 类型定义符typedef 12 位运算 12.1 位运算符C语言提供了六种位运算符: 189 12.1.1 按位与运算 191 12.1.2 按位或运算 ...

    Visual C++ 2010入门经典(第5版)--源代码及课后练习答案

     ·分享c++程序的错误查找技术,并介绍通用的调试原则讨论每一个windows应用程序的结构和基本元素  ·举例说明如何使用mfc开发本地windows应用程序  ·指导读者用c++和c++/cli设计和创建大量的windows应用程序 ...

    3.C++程序设计语言.第1~3部分.原书第4版 中文版有详细书签2016

    第四部分(第30~44章)概述标准库并讨论一些兼容性问题。由于篇幅问题,原书中文版分两册出版,分别对应原书的第一至三部分和第四部分。这一册为第一至三部分。 目录 第3版前言 第2版前言 第1版前言 第一部分 ...

    C++工程师需要掌握的10个C++11特性

    本文讨论了10个C++11中新增的特性,所有的C++开发者都应学习和使用。C++11无论是语言本身还是标准库都新增了许多新的东西,而本文仅仅是介绍了皮毛。...  强类型的枚举类型(Strongly-typed enums)

    Visual C++ 2005入门经典--源代码及课后练习答案

    2.3.6 ISO/ANSI C++中的基本类型 49 2.3.7 字面值 50 2.3.8 定义数据类型的同义词 50 2.3.9 具有特定值集的变量 51 2.3.10 指定枚举常量的类型 52 2.4 基本的输入/输出操作 53 2.4.1 从键盘输入 53 ...

    -C++参考大全(第四版) (2010 年度畅销榜

    其中第一部分全面讨论了C++的C子集;第二部分详细介绍了C++本身的特性,如类和对象、构造函数、析构函数和模板等;第三部分描述了标准函数库;第四部分讨论了标准类库,包括STL(标准模板库);第五部分显示了两个应用...

    [Visual.C++.2010入门经典(第5版)].Ivor.Horton.part1

    2.13.6 c++/cli枚举 92 2.14 查看c++/cli类型 96 2.15 小结 97 2.16 练习 97 2.17 本章主要内容 98 第3章 判断和循环 101 3.1 比较数据值 101 3.1.1 if语句 102 3.1.2 嵌套的if语句 104 3.1.3 嵌套的if-else语句 107...

    C++模板之特化与偏特化详解

    对于C++模板特化和偏特化,对于别人来说,已经不是什么新东西了,但是对于我来说,的确是我的盲区,那天在群里讨论这个问题,自己对于这部分确实没有掌握,又联想到在《STL源码剖析》一书中,对于此也是有着介绍。...

    谭浩强C语言程序设计,C++程序设计,严蔚敏数据结构,高一凡数据结构算法分析与实现.rar )

    11.10.1 枚举类型的定义和枚举变量的说明 184 11.10.2 枚举类型变量的赋值和使用 185 11.11 类型定义符typedef 12 位运算 12.1 位运算符C语言提供了六种位运算符: 189 12.1.1 按位与运算 191 12.1.2 按位或运算 ...

    在一小时内学会 C#(txt版本)

    枚举类型 引用类型 引用类型在堆(heap)中分配内存且当其不再使用时,将自动进行垃圾清理。和 C++ 要求用户显示创建 delete 运算符不一样,它们使用新运算符创建,且没有 delete 运算符。在 C# 中它们自动由...

    《你必须知道的495个C语言问题》

    《你必须知道的495个C语言问题》以问答的形式组织内容,讨论了学习或使用C语言的过程中经常遇到的一些问题。书中列出了C用户经常问的400多个经典问题,涵盖了初始化、数组、指针、字符串、内存分配、库函数、C预...

    语言程序设计课后习题答案

    2-6 在下面的枚举类型中,Blue的值是多少? enum COLOR { WHITE, BLACK = 100, RED, BLUE, GREEN = 300 }; 解: Blue = 102 2-7 注释有什么作用?C++中有哪几种注释的方法?他们之间有什么区别? 解: 注释在...

    你必须知道的495个C语言问题.pdf

     ——Francis Glassborow,著名C/C++专家,ACCU(C/C++用户协会)前主席  “本书清晰地阐明了Kernighan与Ritchie的The C Programming Language一书中许多简略的地方,而且精彩地总结了C语言编程实践,强烈推荐!...

    ASP3《高级编程》(第一部分)

    5.1.1 不同类型的对象和组件 134 5.1.2 VBScript和JScript脚本对象 135 5.2 创建对象和组件实例 136 5.2.1 使用Server.CreateObject方法 136 5.2.2 使用元素 136 5.2.3 Server.CreateObject与的 区别 138 ...

    ASP3《高级编程》(第二部分)

    5.1.1 不同类型的对象和组件 134 5.1.2 VBScript和JScript脚本对象 135 5.2 创建对象和组件实例 136 5.2.1 使用Server.CreateObject方法 136 5.2.2 使用元素 136 5.2.3 Server.CreateObject与的 区别 138 ...

    c#学习笔记.txt

    如前所述,我是一个狮子座男人,一度我认为学习Java会使我看起来与众不同,可是几个月以后我放弃了这个选择,我看了论坛里关于这两种语言孰优孰劣的讨论,最终选择了C#,请不要问我为何做出这样的选择,很多人认为...

Global site tag (gtag.js) - Google Analytics