C++ 枚举类型

本文介绍了C++中枚举类型的使用,包括枚举子的默认值和显式赋值。枚举子的类型与其所在的枚举相同,提供了一种提示变量用途的方式。默认情况下,后续枚举子的值为前一个枚举子加1。同时,枚举类型可以用于初始化,但必须使用枚举子,直接赋整数值会导致错误。
1、枚举enum的用途浅例
      写程序时,我们常常需要为某个对象关联一组可选alternative属性.例如,学生的成绩分A,B,C,D等,天气分sunny, cloudy, rainy等等。
      更常见的,打开一个文件可能有三种状态:input, output和append. 典型做法是,对应定义3个常数,即:
      const int input = 1;
      const int output = 2;
      const int append = 3;
然后,调用以下函数:
      bool open_file(string file_name, int open_mode);
比如,
    open_file("Phenix_and_the_Crane", append);
       这种做法比较简单,但存在许多缺点,主要的一点就是无法限制传递给open_file函数的第2个参数的取值范围,只要传递int类型的值都是合法的。(当然,这样的情况下的应对措施就是在open_file函数内部判断第二个参数的取值,只有在1,2,3范围内才处理。)
       使用枚举能在一定程度上减轻这种尴尬,它不但能实现类似于之前定义三个常量的功能,还能够将这三个值组合起来成为独一无二的组。例如:
      enum open_modes {input = 1, output, append};
      以上定义了open_modes为枚举类型enumeration type。每一个命名了的枚举都是唯一的类型,是一个类型标示器type specifier。例如,我们可以重新写一个open_file函数:
      bool open_file(string file_name, open_modes om);
      在open_modes枚举中,input, output, append称为枚举子enumerator, 它们限定了open_modes定义的对象的取值范围。这个时候,调用open_file函数和之前的方法还是一模一样:
     open_file("Phenix_and_the_Crane", append);
     但是,如果传递给open_file的第二个参数不是open_modes枚举类型值的话,那么编译器就会识别出错误;就算该参数取值等价于input, output, append中的某个,
也一样会出错哦!例如:

     open_file("Phenix_and_the_Crane", 1);


2 枚举子的类型和取值

      枚举子的类型就是它所在的那个枚举,例如前面说到的open_modes枚举中,input,output和append等枚举子的类型都是open_modes。

      这种做法,其实是为了赋予用户和编译器一些有关该变量拟议中的用途的提示。

      默认下,第一个枚举子被赋值0,接下来的枚举子取值是前面一个枚举子的取值+1,例如:
      enum weather {sunny, cloudy, rainy, windy};
其中
      sunny == 0,
      cloudy == 1,
      rainy == 2,

      windy == 3;

以上是默认情况,有时候我们希望显式地指定某个枚举子的值,那么会出现什么情况呢?看看:

       enum some_fruit {apple = 3, orange, banana = 4, bear};

       好了,apple == 3, banana == 4; 那么orange和bear呢?记得前面说过一句,默认下”接下来的枚举子取值是前面一个枚举子的取值+1“。

        既然这两个枚举子没有显式赋值,那么就按照默认规则办事,所以 orange == 4, bear == 5.

     
3、枚举变量的定义、初始化和赋值
     既然每个枚举都是一个类型,那么由这个类型自然可以声明变量,例如,由前面定义的some_big_cities:some_big_cities where_I_am;
     需要注意的是,在声明where_I_am时没有初始化,如果这时打印where_I_am的值:
     enum some_big_cities {
                                            Guangzhou = 4,

                                            Shenzhen = 4,

                                             Hongkong = 4,

                                            Shanghai = 2,

                                            Beijing = 3,

                                            Chongqi = 5

                                                 };

int main(void)
{
     some_big_cities wh;
     cout<<"the value is: "<<wh<<endl;
     return 0;
}
输出将是the value is: 1. 然而,如果声明wh为全局变量,则另一种情况:
enum some_big_cities {Guangzhou = 1 Shenzhen = 1, Hongkong = 1,
                                       Shanghai = 2, Beijing = 3, Chongqi = 5};
some_big_cities wh;
int main(void)
{
   cout<<"the value is: "<<wh<<endl;  
   return 0;
}
输出将是the value is: 0;
      以上结果是在Visual C++ 2005 Express中得到,不知道其它编译器情况如何,也不知为什么得到这样的结果。下来再找找资料。
     定义一个枚举变量时,可以给它初始化,例如:
     some_big_cities wh = Guangzhou;

     注意等号右边只能取枚举子中的某一个;

     特别地,以Guangzhou为例,虽然Guangzhou==4, 但以下初始化是出错的:some_big_cities wh = 4;

      Visual C++ 2005编译器提示:
       error C2440: 'initializing' : cannot convert from 'int' to 'some_big_cities'
      可见,不能直接地把一个整型赋值给一个枚举变量,因为枚举和整型是不同类型的,除非显式转换。关于枚举与整型的关系,后面再讲。
      除了初始化,枚举变量也有赋值运算:
      some_big_cities wh;
      wh = Guangzhou;
      wh = Shanghai;
或者
      some_big_cities wh1 = Guangzhou;
      some_big_cities wh2 = Shanghai;

      wh2 = wh1;


4、枚举的取值范围
   如果某个枚举中所有枚举子的值均非负,该枚举的表示范围就是[0:2^k-1],其中2^k是能使所有枚举子都位于此范围内的最小的2的幂;如果存在负的枚举值,该枚举的取值范围就是[-2^k,2^k-1].例如:
    enum e1 {dark, light}; //范围0:1

    enum e3 {min = -10, max = 1000}; //范围-1024:1023


5、枚举与整型的关系
    整型值只能显式地转换成一个枚举值,但是,如果转换的结果位于该枚举取值范围之外,则结果是无定义的。
     enum e1 {dark = 1, light = 10};
     e1 VAR1 = e1(50); //无定义
     e1 VAR2 = e1(3); //编译通过
     在这里也说明了不允许隐式地从整型转换到枚举的原因,因为大部分整型值在特定的枚举里没有对应的表示。
     至于枚举可以当作特定的整型数来用的例子,从open_modes可以体会。




6、Sizeof

    一个枚举类型的sizeof就是某个能够容纳其范围的整型的sizeof, 而且不会大于sizeof(int), 除非某个枚举子的值不能用int或者unsigned int来表示。
      在32位机器中,sizeof(int)一般等于4。前面介绍的所有枚举,例如,
enum SomeCities
{
   zhanjiang,
   Maoming,
   Yangjiang,
   Jiangmen,
   Zhongshan
};

计算其sizeof, 可能是1,也可能是是4。在我的intel E2160双核、32位机器中,得到4。
-----------------------------------------------------------------------------------
[注1, Begin]
由于通过将整型数显式转换就可能得到对应枚举类型的值,所以声明一个枚举来达到限制传递给函数的参数取值范围还是力不从心的,以下是一个例子:

enum SomeCities
{
zhanjiang=1, //1
Maoming,     //2
Yangjiang,   //3
Jiangmen,   //4
Zhongshan = 1000 //1000
};
void printEnum(SomeCities sc)
{
cout<<sc<<endl;
}
int main(void)
{
SomeCities oneCity = SomeCities(50); //将50通过显式转换,为oneCity赋值
printEnum(oneCity); //在VC++ 6 编译器下得到50输出
return 0;
}

以上例子说明,虽然SomeCities的定义里没有赋值为50的枚举值,但是,由于50在该枚举的取值范围内,所以通过显式声明得到一个有定义的枚举值,从而成功传递给printEnum函数。
<think> 根据用户的问题,用户想了解C++枚举类型的相关信息。结合系统指令和站内引用内容,我将从以下几个方面进行介绍: 1. 枚举类型的定义和基本用法 2. 枚举类型的特性(默认、赋等) 3. 枚举类型的作用域问题 4. C++11引入的强类型枚举(enum class) 同时,我会在回答结束后生成相关问题。 ### 1. C++枚举类型的定义和基本用法 枚举类型(enumeration)是C++中一种用户定义的派生数据类型,用于定义一组命名的整数常量。其基本语法格式为: ```cpp enum 类型名 {枚举常量表}; ``` 其中,枚举常量表列出枚举类型的所有可能取,各枚举常量之间用逗号分隔。例如: ```cpp enum Color { RED, GREEN, BLUE }; // 定义颜色枚举 ``` 这里定义了一个名为`Color`的枚举类型,包含三个枚举常量:RED、GREEN和BLUE。 定义枚举变量: ```cpp Color myColor = RED; ``` ### 2. 枚举类型的特性 #### 默认规则 默认情况下,枚举常量的从0开始,依次递增。例如: ```cpp enum Week { Mon, Tue, Wed, Thu, Fri, Sat, Sun }; ``` - `Mon`为0,`Tue`为1,...,`Sun`为6。 #### 显式赋 可以给枚举常量显式赋,未被赋的常量将按顺序递增: ```cpp enum HttpStatus { OK=200, Created=201, Accepted=202, BadRequest=400 }; ``` - 这里`OK`为200,`Created`为201,`Accepted`为202,`BadRequest`为400。 #### 枚举常量的可以重复 C++允许不同的枚举常量具有相同的,但通常不建议这样做: ```cpp enum { A=1, B=1, C=1 }; // 合法但不推荐 ``` ### 3. 枚举类型的作用域问题(传统枚举的局限性) 传统枚举(非enum class)存在作用域问题:**枚举常量会污染外层作用域**。例如: ```cpp enum Color { RED, GREEN, BLUE }; enum TrafficLight { RED, YELLOW, GREEN }; // 错误!RED和GREEN重定义 ``` 由于`RED`和`GREEN`已经在`Color`中定义,在同一个作用域下无法再次定义。 ### 4. C++11强类型枚举(enum class) 为解决传统枚举的作用域和类型安全问题,C++11引入了强类型枚举(`enum class`): ```cpp enum class Color { RED, GREEN, BLUE }; enum class TrafficLight { RED, YELLOW, GREEN }; // 合法,不冲突 ``` #### 强类型枚举的特点: - **作用域限定**:枚举常量必须通过类型名访问(如`Color::RED`)。 - **不能隐式转换为整数**:需要显式转换(`static_cast<int>(Color::RED)`)。 - **可以显式指定底层类型**(如`enum class Status : uint16_t {...}`),节省内存或明确大小。 #### 示例代码 ```cpp #include <iostream> #include <cstdint> // 用于uint16_t int main() { enum class Status : uint16_t { OK = 200, Error = 404, Timeout = 503 }; Status s = Status::OK; std::cout << static_cast<uint16_t>(s); // 输出200 } ``` ### 总结 - **传统枚举**:简单易用,但存在作用域污染和隐式转换问题。 - **强类型枚举C++11)**:更安全,推荐在新项目中使用。 §§相关问题§§ 1. 如何将枚举类型转换为字符串? 2. 枚举类型在内存中是如何存储的? 3. 如何遍历枚举类型的所有? 4. 在C++11之前,如何避免传统枚举的作用域污染? </think> ### C++枚举类型详解 #### 1. 基本概念 枚举类型(enumeration)是C++中一种用户定义的派生数据类型,用于创建一组命名的整数常量(称为枚举量)。通过`enum`关键字定义,语法格式为: ```cpp enum 类型名 {枚举常量表}; ``` 例如定义一个颜色枚举: ```cpp enum Color { RED, GREEN, BLUE }; // 基础枚举类型定义 ``` 这里创建了`Color`数据类型,包含三个枚举常量:RED、GREEN、BLUE。 #### 2. 核心特性 1. **默认赋规则**: - 枚举量默认从0开始自动赋 - 后续枚举依次递增 ```cpp enum Week { MON, TUE, WED }; // MON=0, TUE=1, WED=2 ``` 2. **显式赋**: - 可以手动指定枚举量的 - 未赋枚举量继承前一个+1 ```cpp enum HttpStatus { OK = 200, Created = 201, Accepted = 202, BadRequest = 400 // 显式赋 }; ``` 3. **作用域特性**: - 传统枚举的常量暴露在外部作用域(可能造成命名污染) ```cpp enum Color { RED, BLUE }; enum TrafficLight { RED, GREEN }; // 错误!RED重定义 ``` #### 3. 使用方式 ```cpp // 定义枚举类型 enum Direction { NORTH, SOUTH, EAST, WEST }; // 声明枚举变量 Direction dir = NORTH; // 作为函数参数 void setDirection(Direction d) { if(d == NORTH) { /* ... */ } } // 遍历枚举 for(int i = NORTH; i <= WEST; i++) { cout << i << " "; // 输出:0 1 2 3 } ``` #### 4. C++11强类型枚举(enum class) 解决传统枚举的缺陷: ```cpp enum class Color { RED, GREEN, BLUE }; // 作用域受限 enum class TrafficLight { RED, YELLOW }; // 无冲突 Color c = Color::RED; // 必须使用作用域限定符 int val = static_cast<int>(c); // 需要显式类型转换 // 指定底层数据类型 enum class Status : uint16_t { OK = 200, ERROR = 500 }; ``` **强类型枚举优势**: - ✅ 避免命名污染(作用域限定) - ✅ 禁止隐式类型转换 - ✅ 可指定底层类型(如uint8_t节省内存) - ✅ 支持前置声明 #### 5. 应用场景 1. 状态机实现(如游戏角色状态) 2. 错误码分类管理 3. 选项配置(如窗口样式) 4. 提高代码可读性(替代魔数) > 枚举类型使程序更易读、易维护,尤其在需要限定取范围的场景中。C++11的enum class解决了传统枚举的作用域和类型安全问题,是现代C++的推荐用法。[^1][^2][^3][^4][^5]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值