为啥需要枚举类型

编程语言中的所有特性都是为了满足某种需求,达到某个目的还出现.不会莫名其妙的出现在那.

枚举可以用来保存一组属性的值.enum的全称是enumeration意思是列举

看着这句话可能觉得太书面化了,不够通俗易懂.那举些通俗的例子说说.日常生活中我们特喜欢分类,比如读书时分啥数,理,化.当官的级别有啥省长,市长,县长.军队有军长,师长,团长.这样一组组的属性值就最适合用枚举类型来表示.当用一个软件时,有些页面会有很多单选按钮(radio button),这也特别适合用枚举来表示你举了哪一个.

光这样说你可能还不能体现枚举的好处.如果没枚举,表示一些组属性的值你只能用一组数字,或者一组字符串.

数字从字面上看不出任意意义,可读性非常差,所以很少用.那就假如要你通过比较字符串来做很多种类判断,比如 if(HisTitle == "stadholder")   else if(HistTile == "mayor") .如果让你敲个几十次你就知道是件多麻烦痛苦的事了,很多单词如果敲错一个意思就完全变了,这样出现bug了也不容易找到.老是复制粘贴也较麻烦.所以字符串是编辑麻烦,容易出错.如果要使用枚举就极大的方便我们敲代码,集成开发工具中的智能感应会给你提示,敲个点号就带出来了.而且枚举会做类型检查,不会像字符串那样只能靠你自己去对比.

枚举类型的内存分配问题

上面我们讲了如果没有枚举,一般会想到用数字或字符串表示某个类别.这样使用肯定不方便.也许你可能会想到用宏来表示.比如#define 市长 "mayor" 或者#define 市长 2

这自然是一个方法,但一来嘛在C++中是不太推荐用宏的,尽量少用.因为C++是强类型的语言,希望通过类型检查来降低程序中的很多错误,而宏只是在编译期前做简单替换,绕过了类型检查,失去了强类型系统的优势支撑. 二来嘛一组属性值都是相关联的信息,必须放到一起,放到一组.

关于常量的误解

枚举类型成员是常量

这句话怎么理解呢.也就是说enum  MyEnum{ one = 1 , two , three} ;

与 const int one = 1;  const int two = 2; const int three = 3; 差不多是一样的.

说到常量其实有个非常误导人的地方因为用宏#define 可以定义的我们说是常量,这里只涉及到简单的替换自然不可能存在内存分配问题.但是用const定义的也叫常量,而const定义常量貌似跟定义一般的变量只多个const关键字. 你可能会想当然认为常量都只是简单替换,所以不存在内存分配.那按这个逻辑,岂不是const定义的常量,枚举类型都没有内存分配?

实际上大部分时候确实是这样的.但并非总是如此,有些情况会需要分配内存的.

1.不需要分配内存的情况

如果定义常量const int one = 1;然后在其他地方只是把one作为右值赋值给其他变量那就不存在内存分配.但这里的常量跟#define定义的常量不同,宏定义的常量是编译前简单替换掉,而不需要做类型检查.而const定义的常量在编译时会帮类型检查,编译完之后再做替换.所以编译完之后就看不到const的信息了,转换成对应的值.const定义的信息只是保存在符号表中.

那同样,如果只是enum MyEnum{ one = 1 , two , three} ;这样定义一个枚举类型,然后也是简单的作右值赋值给其他变量.比如int num = MyEnum::one;那也只是保存信息在符号表中,编译后被替换掉了.

有人可能说如果用sizeof MyEnum测下会发现会是4(这是VS里面,不同的编译器可能不一样)于是认为不管是枚举里面有多少个元素内存分配都是4.实际上不是这意思,应该是定义一个MyEnum类型的枚举变量时会分配内存.这跟定义了一个类一样,你用sizeof去测一个为也会看到大小,但我们知道只有当类实例化之后才实际分配内存的.

2.需要分配内存的情况

1.)const int one;是类的成员变量 2. )extern const int one = 123;    3.)const int one = 1;    int* pConst = &one;

上面三种情况会需要分配内存.

而枚举类型,如果不是简单的去给其他变量赋值,而是去定义一个枚举类型变量.

比如MyEnum grade = MyEnum::one; //此时会分配4字节内存空间.(不过据说编译器会做优化,如果枚举类型所有值用两个字节表示就足够了,那实际分配的会就只会是两字节了.不一定就是默认的int类型的长度)

枚举类型具体用法

一般的用法是在全局域内定义一个枚举类型.比如

enum  MyEnum { one, two, three }

如果不显式指定,就会把第一个值默认赋值为0,然后递增1依次赋值.如果显式指定了某个值,则它下一个是它加1.

所以上面的例子中默认one = 0; two = 1; three= 2;

如果显式指定enum MyEnum { one, two = 3, three }

则one = 0; two = 3; three = 4;

定义一个枚举类型就是MyEnum grade = MyEnum::one;

类中使用枚举这是不太常用的用法.

在类中声明一个枚举后,定义枚举类型就可以省掉那个域作用前缀.比如MyEnum my = one; 在相同的作用域内也不能出现某个变量的名字和枚举中的元素名字相同,也就是不能出现其他变量名字是on,two, three

另外枚举还有一种少见的用法是

enum { one ,two ,three};  就是不指定一个名字,这样我们自然也没法去定义一些枚举类型了.此时就相当于const int one = 0;这样定义三个常量一样.

然后用的话就是int no = one;

初始化时可以赋负数, 以后的标识符仍依次加1;

x = 2;
是不允许是,如果对X进行赋值,只能对3进行类型转换.即:
x = (string)2;
那么这样就对了.
如果给x赋的不是一个整形的数,而是一个字符型的,如:
x = (string)’a’;
那么这时候x的值并不是字符’a’,而是’a’的ASCII码,我们知道,在枚举类型中,各常量的值只能是整形的,所以在对上例会自动的将’a’转换成一个整数值.从内存的角度来看来话,其实C/C++中整形和字符型的变量是一样的,它们之间可以互相转换.

比如定义
namespace A
{
    enum B { b1, b2};
    class C
    {
    };
}

其中我们认为B是一种类型,在类型这个方面我们可以理解enmu跟class,struct是平等的,所以我们可以放心的定义
A::B = A::b1;

注意右边的赋值,本质上b1是直接定义在命名空间A之内的,他相当于A的一个public的const量。
有时候在命名空间中直接定义了太多的enmu是不合理的,这样会污染命名空间,所以,尽可能的,我们要在类的内部定义enmu变量。

同样,关于enum的默认数值的问题需要主义。enmu总是从0开始的,如果我们不指定默认值,则两个在同样的命名空间的enum将会都从0开始,大部分时候这并不会出现问题,但是为了防患于未然,我们尽量要
1. 将enum定义在合适的命名空间中 
2. 为enum指定默认值

 

C++ enum的更多相关文章

  1. Swift enum(枚举)使用范例

    //: Playground - noun: a place where people can play import UIKit var str = "Hello, playground& ...

  2. 枚举:enum

    枚举 所谓枚举就是指定好取值范围,所有内容只能从指定范围取得. 例如,想定义一个color类,他只能有RED,GREEN,BLUE三种植. 使用简单类完成颜色固定取值问题. 1,就是说,一个类只能完成 ...

  3. Asp.Net 将枚举类型(enum)绑定到ListControl(DropDownList)控件

    在开发过程中一些状态的表示使用到枚举类型,那么如何将枚举类型直接绑定到ListControl(DropDownList)是本次的主题,废话不多说了,直接代码: 首先看工具类代码: /// <su ...

  4. 用枚举enum替代int常量

    枚举的好处: 1. 类型安全性 2.使用方便性 public class EnumDemo { enum Color{ RED(3),BLUE(5),BLACK(8),YELLOW(13),GREEN ...

  5. The Java Enum: A Singleton Pattern [reproduced]

    The singleton pattern restricts the instantiation of a class to one object. In Java, to enforce this ...

  6. c# (ENUM)枚举组合类型的谷歌序列化Protobuf

    c# (ENUM)枚举组合类型的谷歌序列化Protobuf,必须在序列化/反序列化时加上下面: RuntimeTypeModel.Default[typeof(Alarm)].EnumPassthru ...

  7. (转)C# Enum,Int,String的互相转换 枚举转换

    Enum为枚举提供基类,其基础类型可以是除 Char 外的任何整型.如果没有显式声明基础类型,则使用 Int32.编程语言通常提供语法来声明由一组已命名的常数和它们的值组成的枚举. 注意:枚举类型的基 ...

  8. set和enum类型的用法和区别

    mysql中的set和enum类型的用法和区别 mysql中的enum和set其实都是string类型的而且只能在指定的集合里取值, 不同的是set可以取多个值,enum只能取一个值.   1 2 3 ...

  9. java enum

    小谈Java Enum的多态性 博客分类: Java JavaAppleJDKJVMIDEA  Enum+多态,我没说错,不过Enum是不可以被继承的,也不可以继承自别人,只是能实现接口而已,何谈多态 ...

  10. enum 与 enum class

    c++11中引入了新的枚举类型---->强制枚举类型 // unscoped enum: enum [identifier] [: type] {enum-list};  // scoped e ...

随机推荐

  1. bootstrap布局 网格系统

    Bootstrap 网格系统 本章节我们将讲解 Bootstrap 的网格系统(Grid System). Bootstrap 提供了一套响应式.移动设备优先的流式网格系统,随着屏幕或视口(viewp ...

  2. 用PHP实现Windows域验证

    系统集成中,可能会有这种需求 Windows 域验证本质上是LDAP验证 但在网上居然找不到详细的技术文档,可见不受待见之极.

  3. How Tomcat Works读书笔记之升级架构

    上一篇HttpServer类职责很多,包括启动服务器,创建ServerSocket,得到客户端Socket,创建Request对象和Response对象,并解析Http请求,这样很混乱,不利于以后服务 ...

  4. LGLCalender (价格日历)

    一直未能找到自己想要的日历价格,就算右也不是我想要的,今天自己封装了一个,欢迎各位来查阅,不足的地方请指教 最新代码下载地址https://github.com/liguoliangiOS/LGLCa ...

  5. java猜数字游戏

    import java.util.Scanner; //导入包 class GuessNum { public static void main(String[] args) { int num = ...

  6. 【iOS】Quartz2D练习-动态改变属性值

    一.通过slider控制圆的缩放 1.实现过程 新建一个项目,新建一个继承自UIview的类,并和storyboard中自定义的view进行关联.代码示例:SLViewController.m文件 # ...

  7. [翻译]:SQL死锁-锁的类型

    很久没有写博客了,这里面的原因有很多.最近的一个项目由于客户明确提出要做下性能压力测试,使用的工具就是VS自带的压力测试工具.以前其它项目做压力测试后反馈的其中一个重要问题就是数据库的死锁.没想到我们 ...

  8. JS之跨域

    今天学了跨域,迫不及待想跟大家分享!不妥之处希望大家指正. 首先来明确一下"跨域"这个概念. 跨域指的是,到外域去取数据.那什么是"外域"呢?我们先来了解同域. ...

  9. ASP.NET MVC 微信公共平台开发之 微信接入

    ASP.NET MVC 接入微信公共平台 申请微信公共账号 既然要接入微信公共平台,微信公共号是必须的(当然如果只是测试的话也可以申请微信公共平台接口测试账号),来这里微信公共平台 申请微信公共号(注 ...

  10. 通过sftp实现文件分发功能

    1       环境: 分发服务器:ubuntu server 64bit,192.168.56.22 接受服务器:windows server 2008,192.168.56.102 2       ...