C++的枚举类型

C的时代

枚举类型

在代码中直接写出来的常量,我们称之为“魔数”。例如:

int week = 1;

你说这个week是星期一,也有人说这个week应该是星期日。这玩意太容易引起歧义,让人摸不着头脑,如同莫名其妙的魔术,所以我们称之为“魔数”。

问题的关键是我们应该给这个常量一个确切的名字:

int monday = 1;

这看起来好多了,不会引起歧义了,于是你愉快地继续写道:

int monday = 1;
int tuesday = 2;
int wednesday = 3;
int thursday = 4;
int friday = 5;
int saturday = 6;
int sunday = 7;

没错,你搞出来了一堆的全局变量。不过别担心,这在C语言中是常规操作,没人会说什么。

但是这里还有一个问题,我们从这些全局变量中完全看不出它们应该是一起的?现在它们就是一帮散兵游勇,而你迫切需要把它们组个朋友圈。于是,C语言说,好吧,那我们就创造一个枚举的概念吧:

enum Week
{
	Monday,
	Tuesday,
	Wednesday,
	Thursday,
	Friday,
	Saturday,
	Sunday,
};

现在枚举是一种类型了,尽管这个改进比直接用全局变量强不了多少,但无论如何,还是勉强可以用的:

	Week week = Monday;
	week = Tuesday;

整型提升

很快,新的问题又冒出来了,枚举该怎么打印呢?

	Week week = Monday;
	week = Tuesday;

    std::cout << week << Wednesday;

你用IDE尝试了一下,然后看到输出了一个1,一个2。“就这?我想输出它的名称啊,而不是一个数字。”,你有些无语。

C编译器面对你的质问有些羞愧:“我确实不知道该怎么输出枚举,实际上,为了输出这些数字,我已经不得不扩展了整型提升的规则。”

你有些惊讶:“”整型提升?就像下面这个?“

	char c = 'a';
	int cc = c;

C编译器涨红的脸变得更红了,“对,就是这个,你也知道,我会的不多。”

你心头一惊,有种不好的预感,“那岂不是说,这枚举还能运算?”

你飞快的敲下了下面的代码:

#include <iostream>

enum Week
{
	Monday,
	Tuesday,
	Wednesday,
	Thursday,
	Friday,
	Saturday,
	Sunday,
};

enum Season
{
	spring, // 春
	summer,	// 夏
	autumn,	// 秋			
	winter,	// 冬
};

int main()
{
	Week week = Monday;
	week = Tuesday;

	int m = week + 1;
	bool is = week > spring;

    std::cout << week << Wednesday;
}

果然,这枚举居然会算术运算,还会和其它的枚举进行比较,这是什么狗屁的类型?一个怪物吗?说好的强类型语言呢?

总结

好吧,无论你喜欢不喜欢,C语言的枚举就是这个鬼样子。

优点:

  1. 是个类型,勉强能用

缺点:

  1. 作用域有问题,没有局部化,会污染当前的名称空间。
  2. 整型提升,确实不得不用,但是也真的不严谨啊

C++98的时代

早期的C++直接继承了C的全部遗产,所以C的枚举也同时继承过来了。

img

“真是丑陋的玩意。”,老B大叔嘟囔了一声,然后就走了,啥也没干。所以C++98的枚举就是C的枚举。

老B大叔是有这个底气跳过这个小问题的,因为他知道C++程序员自己肯定会解决这个问题的。“不就是一个设计实现一个类似于枚举的新类型嘛,这个太简单了。”。于是我们就看到了下面的代码:

#include "pch.h"
#include "CppUnitTest.h"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

#include <utility>

using namespace std::rel_ops;

class WeekType
{
public:
	enum Week
	{
		_Monday,
		_Tuesday,
		_Wednesday,
		_Thursday,
		_Friday,
		_Saturday,
		_Sunday,
	};

	Week _self;

public:
	WeekType(Week week)
		:_self(week)
	{
	}

	bool operator<(const WeekType& other) const
	{
		return _self < other._self;
	}

	bool operator>(const WeekType& other) const
	{
		return _self > other._self;
	}

	const static WeekType Monday;
	const static WeekType Tuesday;
	const static WeekType Wednesday;
	const static WeekType Thursday;
	const static WeekType Friday;
	const static WeekType Saturday;
	const static WeekType Sunday;
};

const WeekType WeekType::Monday(WeekType::_Monday);
const WeekType WeekType::Tuesday(WeekType::_Tuesday);
const WeekType WeekType::Wednesday(WeekType::_Wednesday);
const WeekType WeekType::Thursday(WeekType::_Thursday);
const WeekType WeekType::Friday(WeekType::_Friday);
const WeekType WeekType::Saturday(WeekType::_Saturday);
const WeekType WeekType::Sunday(WeekType::_Sunday);

namespace UnitTestHello
{
	TEST_CLASS(UnitTestEnum)
	{
	public:

		TEST_METHOD(TestWeekType)
		{
			WeekType week = WeekType::Monday;

			Assert::IsTrue(week < WeekType::Sunday);
			Assert::IsTrue(week <= WeekType::Sunday);
		}
	};
}

作用域问题搞定;整型提升的问题搞定。就这?分分钟的事情嘛。

在C++98的时代,关于枚举,C++程序员有两个选择:

  1. 如果追求效率,那就直接用C的枚举
  2. 如果追求严谨,那就自定义一个类

C++11的时代

转眼来到了2011年,那些追求严谨同时又被Java、C#等后起之秀惯坏了的C++程序员再也忍受不了为了个破枚举就要写这么多代码的现状了。他们强烈要求,改进C++的枚举语法。

“都21世纪了,再不变法,大C++就要亡了啊。”

新的枚举类型很快被敲定,发布。实际上,这几乎就是将C++自定义类的工作内置到语言而已。还是上面的例子,现在被简化为:

		enum class WeekClass
		{
			Monday,
			Tuesday,
			Wednesday,
			Thursday,
			Friday,
			Saturday,
			Sunday,
		};

		TEST_METHOD(TestWeekClass)
		{
			WeekClass week = WeekClass::Monday;

			Assert::IsTrue(week < WeekClass::Sunday);
			Assert::IsTrue(week <= WeekClass::Sunday);
		}

就这?多了一个class关键字而已。对,就这,现在它被称为“强枚举类型”。

“现在我们甚至可以指定枚举类型底层的数据类型”,新的C++编译器向你献宝似的说。

		enum class WeekByte : unsigned char
		{
			Monday,
			Tuesday,
			Wednesday,
			Thursday,
			Friday,
			Saturday,
			Sunday,
		};

		TEST_METHOD(TestWeekByte)
		{
			WeekByte week = WeekByte::Monday;

			Assert::AreEqual(size_t(1), sizeof(WeekByte));
			Assert::AreEqual(size_t(4), sizeof(Week));
		}

就这?还凑合吧。作为一位老C++程序员,这点小玩意还真是勾不起你的兴致。于是你懒洋洋的摆了摆手:“都散了吧,该干什么干什么去。”

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值