在C++中enum类型仅仅相当于一系列的整数常量,如果要在日志中显示或标准输出打印时需要把整数与一个字符串对应起来,从配置文件中读取时为了配置文件的可读性最好配置的是字符串名称而不是数字,使用enum类型很不方便,而在C#和Java中都可以方便地使用enum类型的toString方法转换成字符串,或使用parse方法来从字符串转换为对应的enum类型。但我们可以使用类来实现类似C#的enum类型,使用其静态成员变量来代替各enum的各值,再增加相应的方法即可,例如实现一个表示一周各天的类:
class Weekday{
private:
typedef enum{ _Sunday, _Monday, _Tuesday, _Wednesday, _Thursday,_Friday, _Saturday , _END} WeekdayValue;
static const char* _names[];
const WeekdayValue _value;
Weekday(const WeekdayValue value)
:_value(value)
{
}
public:
int Value( void ) const { return _value; }
const char* Name( void ) const { return _names[_value]; }
operator int( void ) const { return (int)_value; }
public:
static Weekday Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday;
static Weekday Parse(const char* str);
static const char** GetNames( void ) { return _names; }
};
const char* Weekday::_names[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday","Friday", "Saturday" };
Weekday Weekday::Parse( const char* str )
{
for(int i=0; i<sizeof></sizeof> if( stricmp(str, _names[i]) == 0){
return Weekday((WeekdayValue)i);
}
}
throw std::exception("Not a valid Weekday name");
}
使用示例:
int main( void )
{
Weekday d0 = Weekday::FromValue(0);
cout
Weekday d6 = Weekday::FromValue(6);
cout
cout
Weekday d5 = Weekday::Parse("FRIDAY");
cout return 0;
}
但是如果每次我们定义一下这样的类都写这么多代码显然有点儿麻烦,而且很多东西是重复的,可以通过使用宏来简化编码,分别定义两个宏,DeclareEnumN和ImplementEnumN,前者用于生成声明,后者用于声明定义,其中的N表示包含的成员的个数,由于宏不支持宏名的重载,只能通过不同宏名称来区分。这样我们在定义枚举类时需要在.hpp的头文件中来使用DeclareEnumN进行声明,在.cpp的源程序文件中使用ImplementEnumN来定义。宏的实现代码如文件enum_class.hpp:
// enum_class.hpp
#ifndef ENUM_CLASS_HPP_H_
#define ENUM_CLASS_HPP_H_
#include <cstring></cstring>
/** common */
#define DECLARE_ENUM_COMMON_METHODS( C) /
private: /
static const char* _names[]; /
const EnumValue _value; /
explicit C(const EnumValue value) /
:_value(value) /
{ /
if(_value > _END) /
throw std::exception("Invalid value of "#C); /
} /
public: /
int Value( void ) const { return _value; } /
const char* Name( void ) const { return _names[_value]; } /
operator int( void ) const { return (int)_value; } /
public: /
inline static const char** GetNames( void ) { return _names; } /
static C FromValue(const int value ); /
static C Parse(const char* str)
#define IMPLEMENT_ENUM_COMMON_METHODS( C ) /
C C::Parse( const char* str ) /
{ /
for(int i=0; i<sizeof></sizeof> if( stricmp(str, _names[i]) == 0){ /
return C((EnumValue)i); /
} /
} /
throw std::exception("Not a valid "#C " name"); /
}
/** 2 enum values */
#if 1
#define DeclareEnum2(C, E1, E2) /
class C{ /
private: typedef enum{ _##E1, _##E2, _END} EnumValue; /
public: static C E1, E2; /
DECLARE_ENUM_COMMON_METHODS( C ); /
};
#define ImplementEnum2(C, E1, E2) /
const char* C::_names[] = {""#E1, ""#E2}; /
C C::E1(C::_##E1); /
C C::E2(C::_##E2); /
IMPLEMENT_ENUM_COMMON_METHODS( C)
#endif
/** 3 enum values */
#if 1
#define DeclareEnum3(C, E1, E2, E3) /
class C{ /
private: typedef enum{ _##E1, _##E2, _##E3, _END} EnumValue; /
DECLARE_ENUM_COMMON_METHODS( C ); /
public: static C E1, E2, E3; /
};
#define ImplementEnum3(C, E1, E2, E3) /
const char* C::_names[] = {""#E1, ""#E2, ""#E3}; /
C C::E1(C::_##E1); /
C C::E2(C::_##E2); /
C C::E3(C::_##E3); /
IMPLEMENT_ENUM_COMMON_METHODS( C)
#endif
/** 4 enum values */
#if 1
#define DeclareEnum4(C, E1, E2, E3, E4) /
class C{ /
private: typedef enum{ _##E1, _##E2, _##E3, _##E4, _END} EnumValue; /
DECLARE_ENUM_COMMON_METHODS( C ); /
public: static C E1, E2, E3, E4; /
};
#define ImplementEnum4(C, E1, E2, E3, E4) /
const char* C::_names[] = {""#E1, ""#E2, ""#E3, ""#E4}; /
C C::E1(C::_##E1); /
C C::E2(C::_##E2); /
C C::E3(C::_##E3); /
C C::E4(C::_##E4); /
IMPLEMENT_ENUM_COMMON_METHODS( C)
#endif
/** 5 enum values */
#if 1
#define DeclareEnum5(C, E1, E2, E3, E4, E5) /
class C{ /
private: typedef enum{ _##E1, _##E2, _##E3, _##E4, _##E5, _END} EnumValue; /
DECLARE_ENUM_COMMON_METHODS( C ); /
public: static C E1, E2, E3, E4, E5; /
};
#define ImplementEnum5(C, E1, E2, E3, E4, E5) /
const char* C::_names[] = {""#E1, ""#E2, ""#E3, ""#E4, ""#E5}; /
C C::E1(C::_##E1); /
C C::E2(C::_##E2); /
C C::E3(C::_##E3); /
C C::E4(C::_##E4); /
C C::E5(C::_##E5); /
IMPLEMENT_ENUM_COMMON_METHODS( C)
#endif
//** 6 enum values */
#if 1
#define DeclareEnum6(C, E1, E2, E3, E4, E5, E6) /
class C{ /
private: typedef enum{ _##E1, _##E2, _##E3, _##E4, _##E5, _##E6, _END} EnumValue; /
DECLARE_ENUM_COMMON_METHODS( C ); /
public: static C E1, E2, E3, E4, E5, E6; /
};
#define ImplementEnum6(C, E1, E2, E3, E4, E5, E6) /
const char* C::_names[] = {""#E1, ""#E2, ""#E3, ""#E4, ""#E5, ""#E6}; /
C C::E1(C::_##E1); /
C C::E2(C::_##E2); /
C C::E3(C::_##E3); /
C C::E4(C::_##E4); /
C C::E5(C::_##E5); /
C C::E6(C::_##E6); /
IMPLEMENT_ENUM_COMMON_METHODS( C)
#endif
/** 7 enum values */
#if 1
#define DeclareEnum7(C, E1, E2, E3, E4, E5, E6, E7) /
class C{ /
private: typedef enum{ _##E1, _##E2, _##E3, _##E4, _##E5, _##E6, _##E7, _END} EnumValue; /
DECLARE_ENUM_COMMON_METHODS( C ); /
public: static C E1, E2, E3, E4, E5, E6, E7; /
};
#define ImplementEnum7(C, E1, E2, E3, E4, E5, E6, E7) /
const char* C::_names[] = {""#E1, ""#E2, ""#E3, ""#E4, ""#E5, ""#E6, ""#E7}; /
C C::E1(C::_##E1); /
C C::E2(C::_##E2); /
C C::E3(C::_##E3); /
C C::E4(C::_##E4); /
C C::E5(C::_##E5); /
C C::E6(C::_##E6); /
C C::E7(C::_##E7); /
IMPLEMENT_ENUM_COMMON_METHODS( C)
#endif
/** 8 enum values */
#if 1
#define DeclareEnum8(C, E1, E2, E3, E4, E5, E6, E7, E8) /
class C{ /
private: typedef enum{ _##E1, _##E2, _##E3, _##E4, _##E5, _##E6, _##E7, _##E8, _END} EnumValue; /
DECLARE_ENUM_COMMON_METHODS( C ); /
public: static C E1, E2, E3, E4, E5, E6, E7, E8; /
};
#define ImplementEnum8(C, E1, E2, E3, E4, E5, E6, E7, E8) /
const char* C::_names[] = {""#E1, ""#E2, ""#E3, ""#E4, ""#E5, ""#E6, ""#E7, ""#E8}; /
C C::E1(C::_##E1); /
C C::E2(C::_##E2); /
C C::E3(C::_##E3); /
C C::E4(C::_##E4); /
C C::E5(C::_##E5); /
C C::E6(C::_##E6); /
C C::E8(C::_##E7); /
C C::E7(C::_##E8); /
IMPLEMENT_ENUM_COMMON_METHODS( C)
#endif
/** 9 enum values */
#if 1
#define DeclareEnum9(C, E1, E2, E3, E4, E5, E6, E7, E8, E9) /
class C{ /
private: typedef enum{ _##E1, _##E2, _##E3, _##E4, _##E5, _##E6, _##E7, _##E8, _##E9, _END} EnumValue; /
DECLARE_ENUM_COMMON_METHODS( C ); /
public: static C E1, E2, E3, E4, E5, E6, E7, E8, E9; /
};
#define ImplementEnum9(C, E1, E2, E3, E4, E5, E6, E7, E8, E9) /
const char* C::_names[] = {""#E1, ""#E2, ""#E3, ""#E4, ""#E5, ""#E6, ""#E7, ""#E8, ""#E9}; /
C C::E1(C::_##E1); /
C C::E2(C::_##E2); /
C C::E3(C::_##E3); /
C C::E4(C::_##E4); /
C C::E5(C::_##E5); /
C C::E6(C::_##E6); /
C C::E7(C::_##E7); /
C C::E8(C::_##E8); /
C C::E9(C::_##E9); /
IMPLEMENT_ENUM_COMMON_METHODS( C)
#endif
/** 10 enum values */
#if 1
#define DeclareEnum10(C, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10) /
class C{ /
private: typedef enum{ _##E1, _##E2, _##E3, _##E4, _##E5, _##E6, _##E7, _##E8, _##E9, _##E10, _END} EnumValue; /
DECLARE_ENUM_COMMON_METHODS( C ); /
public: static C E1, E2, E3, E4, E5, E6, E7, E8, E9, E10; /
};
#define ImplementEnum10(C, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10) /
const char* C::_names[] = {""#E1, ""#E2, ""#E3, ""#E4, ""#E5, ""#E6, ""#E7, ""#E8, ""#E9, ""#E10}; /
C C::E1(C::_##E1); /
C C::E2(C::_##E2); /
C C::E3(C::_##E3); /
C C::E4(C::_##E4); /
C C::E5(C::_##E5); /
C C::E6(C::_##E6); /
C C::E7(C::_##E7); /
C C::E8(C::_##E8); /
C C::E9(C::_##E9); /
C C::E10(C::_##E10); /
IMPLEMENT_ENUM_COMMON_METHODS( C)
#endif
//------------------
#endif
该文件定义了2-10个参数的宏,如果需要更多的参数可以自行添加,或者不使用宏,而直接利用定义好的DECLARE_ENUM_COMMON_METHODS、IMPLEMENT_ENUM_COMMON_METHODS两个宏,来定义自己的类,也可以省去很多通用编码。使用时,例如在头文件中进行声明:
// enum_class_demo.hpp
#ifndef ENUM_CLASS_DEMO_HPP
#define ENUM_CLASS_DEMO_HPP
#include "enum_class.hpp"
DeclareEnum2(Result, OK, Error);
DeclareEnum3(E3, E3_1, E3_2, E3_3);
DeclareEnum4(E4, E4_1, E4_2, E4_3, E4_4);
DeclareEnum5(E5, E5_1, E5_2, E5_3, E5_4, E5_5);
DeclareEnum6(E6, E6_1, E6_2, E6_3, E6_4, E6_5, E6_6);
DeclareEnum7(E7, E7_1, E7_2, E7_3, E7_4, E7_5, E7_6, E7_7);
DeclareEnum8(E8, E8_1, E8_2, E8_3, E8_4, E8_5, E8_6, E8_7, E8_8);
DeclareEnum9(E9, E9_1, E9_2, E9_3, E9_4, E9_5, E9_6, E9_7, E9_8, E9_9);
DeclareEnum10(E10, E10_1, E10_2, E10_3, E10_4, E10_5, E10_6, E10_7, E10_8, E10_9,E10_10);
DeclareEnum4(Season, Spring, Summer, Autumn, Winter);
#endif
而在源程序enum_class_demo.cpp文件中进行定义,例如:
#include <iostream><br>#include <cstring><br>using namespace std; <br>#include "enum_class_demo.hpp" <br>ImplementEnum2(Result, OK, Error); </cstring></iostream>
ImplementEnum3(E3, E3_1, E3_2, E3_3);
ImplementEnum4(E4, E4_1, E4_2, E4_3, E4_4);
ImplementEnum5(E5, E5_1, E5_2, E5_3, E5_4, E5_5);
ImplementEnum6(E6, E6_1, E6_2, E6_3, E6_4, E6_5, E6_6);
ImplementEnum7(E7, E7_1, E7_2, E7_3, E7_4, E7_5, E7_6, E7_7);
ImplementEnum8(E8, E8_1, E8_2, E8_3, E8_4, E8_5, E8_6, E8_7, E8_8);
ImplementEnum9(E9, E9_1, E9_2, E9_3, E9_4, E9_5, E9_6, E9_7, E9_8, E9_9);
ImplementEnum10(E10, E10_1, E10_2, E10_3, E10_4, E10_5, E10_6, E10_7, E10_8, E10_9,E10_10);
ImplementEnum4(Season, Spring, Summer, Autumn, Winter);
int main( void )
{
cout cout
cout cout cout cout cout cout cout cout
Season ssn = Season::Parse("winter");
cout return 0;
}
这样以后再需要定义类似C#或Java中的enum类时只需要两行就可以了。
但是这各模拟方式还有一个缺点,那就是这里用的值都是连续的,如果要定义不连续的值则需要自行实现。使用连续值的一个最重要的原因就是性能,与符串的映射表很自然地实现为一个指针数组,性能非常高效,再加上inline,可以说从数值到字符串的转换几乎达到了性能的0消耗。
在实际使用中使用enum的绝大多数情况下使用连续值即可,枚举值作为mask使用的情况就更复杂,这样还需要重载实现位操作运算符,但技术上实现是没有问题的,而且性能并不会有太大的损耗,对于硬件比大白菜还便宜的时代,这点儿性能又算得了什么呢?所换来的可读性节约的维护成本是完全可以弥补这点儿损失。
分享到:
相关推荐
NULL 博文链接:https://rensanning.iteye.com/blog/2013734
c#遍历枚举(ENUM)类型的方法,简单实用,适合c#初学者
Java SE程序 Enum枚举类Java SE程序 Enum枚举类Java SE程序 Enum枚举类Java SE程序 Enum枚举类Java SE程序 Enum枚举类Java SE程序 Enum枚举类Java SE程序 Enum枚举类Java SE程序 Enum枚举类Java SE程序 Enum枚举类...
Java中的Enum的使用与分析
C++中枚举类型(enum)
常见的enum类型重定义的解决方法,清晰明了。
C#与C调用C++,非托管,含struct调用及enum公用,完整项目,可直接编译或运行。 项目将所有工程的输出统一到Debug。 vs2015+Framework4.6,注意工程的配置。 所有东西自写,只是出于样例参考的作用,所以代码规范...
java枚举类型的定义使用介绍,还有示例。
STL vector 容器介绍 C++中布尔类型 深入探讨C++中的引用 C/C++中枚举类型(enum)
博文“Java 语言中 Enum 类型的使用介绍”的源码。
C++ 11起引入的 enum class相对于传统的enum有了很多变化,主要是针对传统 enum 在编程过程中出现的值类型名称作用域、enum类型安全问题进行了改良. 一、传统enum类型 先来看看传统enum在编程过程中可能遇到的一些...
Java中的枚举类型Enum示例源代码,详见http://blog.csdn.net/snarlfuture/article/details/18996037
NULL 博文链接:https://janeky.iteye.com/blog/463611
java中enum枚举的详细用法。 0.0
enum day {Sun,Mon,Tue,Wed,Thu,Fri,Sat}; 默认情况下,枚举符的值从0开始,其后值总是前面一个+1。 即Sun=0,Mon=1,Tue=2,Wed=3,Thu=4,Fri=5,Sat=6 也可以自己定义数值,其后值总是前面一个+1 例如: enum day {Sun=...
java enum详细教程。由浅入深,包括基本语法方面..很适合新手学习。/n各位看官。绝对超值。
在C++中,枚举类型分为不限定作用域(enum)和限定作用域(enum class)。 2. enum与enum class的区别? (为什么需要限定作用域?) 答:枚举作用域是指枚举类型成员名字的作用域,起自其声明之处,终止枚举定义...
主要介绍了java 中enum的使用方法详解的相关资料,希望通过本文能帮助到大家,理解掌握java 中enum的使用方法,需要的朋友可以参考下