当前位置: 首页 > news >正文

5.1 C++11强类型枚举

一、C枚举的缺陷

1.类型冲突

枚举值和类型都是全局可见的, 与正常C++的namespace、类等都是格格不入的,并且还容易导致冲突。

enum Type { General, Light, Medium, Heavy };
enum Category { General, Pistol, MachineGun, Cannon };

如果在相同作用域同时能访问到枚举Type和Category,则General会冲突。

当然我们可以通过namespace对全局枚举进行分隔。但使用时如果忘记写namespace,也还是会报错。


namespace T {enum Type { General, Light, Medium, Heavy };
}namespace {enum Category { General };
}#include <iostream>int main()
{T::Type t = T::Heavy;t = General;	//error.无法赋值,不能将匿名的Category::General赋值给T::Typeif (t == General) {	//仅对于匿名命名空间可以直接使用General。std::cout << "equal" << std::endl;}else {std::cout << "not equal" << std::endl;}system("pause");return 0;
}
  • 首先,对于匿名命名空间,或者使用using声明的命名空间,可以直接使用枚举值(15,16行的General),否则需要以命名空间::[枚举类型::]枚举值的方式访问。
  • 虽然可以访问,但是对于不同命名空间的不同枚举只能做比较(因为可以隐式转为int)。但是不能进行赋值操作,因为类型和作用域都不相同。

2.可以隐式转换为int

因为C的枚举是基于常量数值设计的,所以总是可以被隐式转为int,所以在算数运算(没有什么意义)和比较运算时,容易出错。(注意无法赋值)

这是因为隐式转换为整型后,没有了类型限制,则可以随意比较和算数运算。

#include <iostream>
using namespace std;
enum Type { General, Light, Medium, Heavy };
//enum Category { General, Pistol, MachineGun, Cannon }; // 无法编译通过,重复定义
了General
enum Category { Pistol, MachineGun, Cannon };
struct Killer {
Killer(Type t, Category c) : type(t), category(c){}
Type type;
Category category;
};
int main() {Killer cool(General, MachineGun);// ...// ...其他很多代码...// ...if (cool.type >= Pistol)cout << "It is not a pistol" << endl;// ...cout << is_pod<Type>::value << endl;          // 1cout << is_pod<Category>::value << endl;     // 1return 0;
}
// 编译选项:g++ -std=c++11 5-1-2.cpp

3.基础类型不定性

C++所基于的“基础类型”由编译器决定,也就意味着,他的符号性和存储空间是不确定的。

#include <iostream>
using namespace std;
enum C { C1 = 1, C2 = 2};
enum D { D1 = 1, D2 = 2, Dbig = 0xFFFFFFF0U };
enum E { E1 = 1, E2 = 2, Ebig = 0xFFFFFFFFFLL};
int main() {cout << sizeof(C1) << endl;    // 4cout << Dbig << endl;    // 编译器输出不同, g++:4294967280,Vs2017:-16cout << sizeof(D1) << endl;      // 4cout << sizeof(Dbig) << endl;    // 4cout << Ebig << endl;    // g++:68719476735,vs2017:-1cout << sizeof(E1) << endl; // 8return 0;
}
// 编译选项:g++ 5-1-4.cpp

上面可以看到如果够用的话(Dbig),采用4字节存储。不够用的时候会自动扩展为8字节存储(Ebig),且对于Ebig和Dbig而言不同的编译器返回的值不同,这是因为符号性不一样导致。

二、强枚举类型

1.语法:

enum class/struct [enum-name] [:base-type]{};
  • 辅助记忆:因为叫强枚举-类型,所以是enum class 而非 class enum。
  • 将class换成struct并没有任何影响
  • enum-name后可以接基础类型,表示该枚举类型基于此基础类型创建(除wchar_t的其他任意类型)。

2.优点:

  • 强作用域,枚举值对于父作用域不直接可见,需要通过作用域访问
  • 不能隐式转换为int,而需要显示转换
  • 可以指定基础类型,以此确定存储空间和符号性。(这样我们可以在明确不需要太大空间时,指定较小尺寸的类型(如char)节省空间)

可以看到基本上就是为了解决C枚举的三个缺陷而设计的。

3.其他

强枚举类型也是可以匿名的,但是由于其枚举成员需要通过作用域访问,因此匿名强枚举类型可能无法访问成员,当然也可以使用decltype获取类型。

三、对原有枚举类型的扩展

对于C枚举,默认依旧由编译器实现基础类型,但是C++11允许其和强枚举类型一样,指定基础类型。

enum Type: char { General, Light, Medium, Heavy };

其次,在C++11中,枚举成员的名字除了会自动输出到父作用域,也可以在枚举类型定义的作用域内有效。

enum Type { General, Light, Medium, Heavy };
Type t1 = General;
Type t2 = Type::General;
http://www.lryc.cn/news/260973.html

相关文章:

  • Android : BottomNavigation底部导航_简单应用
  • 基于ssm培训学校教学管理平台论文
  • 关于嵌入式开发的一些信息汇总:C标准、芯片架构、编译器、MISRA-C
  • java实现局域网内视频投屏播放(二)爬虫
  • a标签的target属性
  • 无mac在线申请hbuilderx打包ios证书的方法
  • [css] flex wrap 九宫格布局
  • 云上丝绸之路| 云轴科技ZStack成功实践精选(西北)
  • Java8 IfPresent 与 forEach 的组合操作
  • WebGL+Three.js入门与实战——给画布换颜色、绘制一个点、三维坐标系
  • SystemServer 进程启动过程
  • Java EE 多线程之 JUC
  • Unity光照模型实践
  • 从0创建并部署一个网页到服务器
  • Ubuntu 22.04 安装 OCI CLI
  • K8S的安装工具
  • vue中哪些数组的方法可以做到响应式
  • 软考科目如何选择?
  • 羊大师解读,血压波动
  • 关于充值!购买的流量卡第一次在哪充值?这个问题你想过吗?
  • HTML基础标签
  • 人大金仓引领医疗行业新标准
  • 【UML】NO.1 UML简介
  • 【Idea】SpringBoot项目中,jar包引用冲突异常的排查 / SM2算法中使用bcprov-jdk15to18的报错冲突问题
  • MISRA C++ 2023:C和C++测试解决方案实现静态分析
  • 半导体:Gem/Secs基本协议库的开发(4)
  • 解锁知识的新大门:自建知识付费小程序的技术指南
  • Java8实战 - 行为参数化传递代码
  • jmeter,取“临时重定向的登录接口”响应头中的cookie
  • 流程控制之条件判断