找回密码
 立即注册
收起左侧

C++老鸟日记014 枚举&联合

0
回复
5631
查看
[复制链接]
累计签到:41 天
连续签到:1 天
来源: 原创 2018-9-6 18:25:03 显示全部楼层 |阅读模式

马上注册,查看详细内容!注册请先查看:注册须知

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
本帖最后由 baizy77 于 2018-10-1 20:48 编辑

版权声明
---------------------------------------------------------------------------------------------------------------------
该文章原创于Qter开源社区(www.qter.org
作者: 女儿叫老白 (白振勇)
转载请注明出处!
---------------------------------------------------------------------------------------------------------------------
本套课程属于:《C++跨平台开发干货》系列课程。
-----------------------------------------------------------------------------

引言
-----------------------------------------------------------------------------
       我们经常使用宏定义定义常量,而这并不是我们推荐的定义常量的最好的方式,那么定义常量还有啥方法呢?

正文
-----------------------------------------------------------------------------
(3.8.3, 3.8.4)
       --枚举 enum
在编程过程中,我们经常用到一些整数型常量,比如参数类型id,这时我们可以采用宏定义的方式把常量定义为宏定义。如果这些常量之间有计算关系(比如后一个的值=前一个值+1),我们就可以使用枚举。枚举的语法如下:
       enum枚举类型名 {
              自定义枚举字符串1= xxx,
              自定义枚举字符串2= xxx,
              自定义枚举字符串3= xxx,
};
比如:
// 枚举:菜单项ID
enum  EMenuID {
       EMENUID_NULL = 0,    // 无效菜单项
       EMENUID_FILEOPEN,   // 打开文件=1
       EMENUID_SAVE,          // 保存=2

       EMENUID_CUSTOM=1000,  // 用户自定义菜单项起始值
EMENUID_CUSTOM_WRITEDB, // 自定义菜单:写入数据库=1001
};

上述的枚举类型EMenuID,包含了4个枚举值,第一个是“EMENUID_NULL = 0”,表示无效菜单项,当然,您也可以写成EMENUID_NULL = 2.。这跟您的实际需求有关。
枚举值以”,”结束。
EMENUID_FILEOPEN和EMENUID_SAVE是两个新枚举值,因为没有给他们赋值,所以他们的值依次等于前一个值+1。
我们也可以为后面的枚举项直接赋值,比如:
EMENUID_CUSTOM=1000
这表示用户自定义菜单项从1000开始。因此EMENUID_CUSTOM_WRITEDB=1001.

-- 联合-union
我们有时候会定义一些变量,但是这些变量是互斥使用的,比如定义一个事项结构时,我们可能要处理操作类事项:
structsEventOperate {
       string strOperator;        // 操作人员
       string strTime;              // 操作时间
       string strJob;                // 操作内容
};
也需要处理告警事项:
structsEventAlarm {
       time_t tmAlarm;    // 报警时间
       int level;                // 报警等级
string strInfo;        // 报警内容
};

那么我们的类中需要用到操作类事项和告警事项,但是这两种事项又不会同时出现,我们就可以用联合的方式进行处理。
我们先定义事项类型:
enum EEventType{
       EEventType_NULL = 0, // 无效事项
       EEventType_Operate,   // 操作类事项
       EEventType_Alarm,       // 告警类事项
};

struct sEventBody{
       EEventType evtType;    // 事项类型
union {
           sEventOperate     evtOperate;    // 操作类事项
           sEventAlarm         evtAlarm;       // 告警类事项
};
};
这样,sEventBody就可以对两种事项类型进行处理,比如:
sEventBodyevtBody;
swtich (evtBody.evtType){
case EEventType_Operate:
       evtBody.evtOperate;     // 对操作类事项进行处理
break;
case EEventType_Alarm:
       evtBody. evtAlarm;        // 对告警类事项进行处理
break;
       default:
              break;
}
sEventBody在内存中的尺寸=  evtType + max(evtOperate,evtAlarm)。也就是evtType的尺寸 加上 evtOperate,evtAlarm两者中尺寸大的那个。

------------------------总结 ----------------------
1. 尽量使用枚举(enum)而不是常量(具体的数字,比如0x3377),在通信时,如果通信双方均使用常量,那么这些常量就变成魔法数字。因为代码的后续维护人员可能根本不知道这些常量的具体含义。

2.枚举项可以根据需要随时定义为某个具体值。但是一定要给前面的枚举项留下足够的空间,否则就可能出现前面不断增加的枚举项已经远远超过了您定义的当前值。比如
enum eMenuId {
EMENUID_NULL =0,    // 无效菜单项
       EMENUID_FILEOPEN,   // 打开文件=1
       EMENUID_SAVE,          // 保存=2
       EMENUID_CONFIG,      // 配置=3,注:这个枚举项时后来增加的
       EMENUID_MODIFY,      // 修改=4,注:这个枚举项时后来增加的
       EMENUID_HELP,          // 帮助=5,注:这个枚举项时后来增加的
       EMENUID_LOGIN,        // 注册=6,注:这个枚举项时后来增加的

       EMENUID_CUSTOM=5, // 用户自定义菜单项起始值,注:该数值已经有问题
};

3.使用联合(union)时要小心,因为起初定义联合时,可能对象的尺寸很小,但是随着功能的增加或者改变,联合的对象所占据的尺寸可能越来越大,当联合的实体(用联合定义的对象)比较多时,它占据的内存甚至超乎想象。

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

公告
可以关注我们的微信公众号yafeilinux_friends获取最新动态,或者加入QQ会员群进行交流:190741849、186601429(已满) 我知道了