C++中enum枚举类型成员重名问题的解决方法
2011-09-08 09:29
459 查看
注:此文章转自hairetz的博客
C++语言中,对于一个枚举类型(enum),其成员值在所属枚举类型的声明作用域内是不可重复的。这个继承自C语言的特性,使我在写程序时碰到有相同名称的枚举成员时,苦于寻找且方便易读的替代枚举名称。
这在C++程序开发方面带来了许多的不方便,在涉及枚举类型时必须时刻关注与现有的枚举变量是否有重名,在一定程度上限制了命名的自主性,也会降低程序的可读性。而在Visual Basic 6和.net系列语言中,两个不同的Enum类型可以具有相同的成员,在使用时只需加上Enum类型名称。目前就是要在C++中实现这种功能。
一个例子,用以描述一台计算机和一个音箱的类,它们都有一个状态属性State。音箱状态值只有开和关两种,而计算机状态还有休眠状态。由于休眠对于音箱没有任何意义,在严格要求的编码下,对于向音箱赋上休眠状态的无意义举动必须在编译时阻止,因此需在使此两种设备类的状态属性分别两个状态枚举类型,计算机状态和音箱状态,代码如下:
上述代码在编译时就不能通过,因为两个枚举的成员都是全局的,stateOpen和stateClosed都重复出现。因此,现在需要做的就是将这两个状态枚举类型分在两个作用域中声明,可采用的方式是在不同的namespace中声明或在不同的类中声明。
enum ComputerState
{
stateOpen,
stateClosed,
stateSuspended
};
enum SpeakerState
{
stateOpen,
stateClosed
};
class Computer
{
public:
void SetState(ComputerState s) { ... }
};
在不同名称空间中声明枚举的代码如下:
namespace computer
{
enum ComputerState
{
stateOpen,
stateClosed,
stateSuspended
};
};
namespace speaker
{
enum SpeakerState
{
stateOpen,
stateClosed
};
};
using namespace computer;
using namespace speaker;
class Computer
{
public:
void SetState(ComputerState s)
{
if ( s == computer::stateOpen ) printf("State set to Open
");
else if ( s == computer::stateClosed ) printf("State set to Closed
");
else if ( s == computer::stateSuspended )
printf("State set to Suspended
");
}
};
虽然代码编译运行都通过,但在不同的名称空间中声明显然不是个好办法,一是Computer::SetState()方法中状态判断是,状态值(stateOpen等)前面并不是类型名称而是namespace名称。这样在代码可读性方面还是比较差。第二,就是有多少个enum类型,就得用多少个namespace以及using namespace,这在实际使用中是无法忍受的。因此, 目前只能是在class中声明enum类,将enum类型class化。代码修改如下:
class ComputerState
{
public:
enum _ComputerState
{
stateOpen,
stateClosed,
stateSuspended
};
};
class SpeakerState
{
public:
enum _SpeakerState
{
stateOpen,
stateClosed
};
};
class Computer
{
public:
void SetState(ComputerState::_ComputerState s)
{
if ( s == ComputerState::stateOpen )
printf("State set to Open
");
else if ( s == ComputerState::stateClosed )
printf("State set to Closed
");
else if ( s == ComputerState::stateSuspended )
printf("State set to Suspended
");
}
};
上述的每个Enum的作用域限制在一个类中,这样实现了不同enum类型其成员的重,但在使用时的类型表述上还没有统一。因此,根据枚举类型变量常用的几个操作符,对其做重载。代码如下:
class ComputerState
{
public:
enum _ComputerState
{
stateOpen,
stateClosed,
stateSuspended
};
private:
_ComputerState m_val;
public:
ComputerState(): m_val(stateOpen) {};
ComputerState (const _ComputerState& s): m_val(s) { };
bool operator == ( const ComputerState& cs )
{
if ( m_val == cs.m_val ) return true;
else return false;
}
operator _ComputerState() { return m_val; }
};
class SpeakerState
{
public:
enum _SpeakerState
{
stateOpen,
stateClosed
};
private:
_SpeakerState m_val;
public:
SpeakerState(): m_val(stateOpen) {};
SpeakerState (const _SpeakerState& s): m_val(s) { };
bool operator == ( const SpeakerState& cs )
{
if ( m_val == cs.m_val ) return true;
else return false;
}
operator _ComputerState() { return m_val; }
};
上述代码增加了类型值成员变量m_val、类复制构造函数,重载了枚举类的等于比较操作符和类型解包操作符,从而实现了一个枚举类型的类化,实现了枚举成员与枚举类自动组包和解包,在使用上,枚举的使用和VB里面除了"."与"::"在操作符上语言本身的区别外,基本相同。最重要的是在枚举成员在命名时不必因为有重名而使用可读性差的或者增加不必要的区别符号或名称。上述枚举类的使用时代码示例如下
class Computer
{
public:
void SetState(ComputerState s)
{
if ( s == ComputerState::stateOpen ) printf("State set to Open
");
else if ( s == ComputerState::stateClosed ) printf("State set to Closed
");
else if ( s == ComputerState::stateSuspended )
printf("State set to Suspended
");
}
};
class Speaker
{
public:
void SetState(SpeakerState s)
{
if ( s == SpeakerState::stateOpen ) printf("State set to Open
");
else if ( s == SpeakerState::stateClosed ) printf("State set to Closed
");
}
};
int main(int argc, char *argv[])
{
Computer cpt;
Speaker spk;
ComputerState cs = ComputerState::stateClosed;
SpeakerState ss = SpeakerState::stateOpen;
cpt.SetState( ComputerState::stateOpen );
spk.SetState( SpeakerState::stateOpen );
cpt.SetState( cs );
spk.SetState( ss );
return EXIT_SUCCESS;
}
但是,由于enum的封装时增加了额外的构造函数和重载操作符,这部分代码将增加不少的工作量。为了减少这部分工作量,可以将这部分增加的函数定义成宏,如下:
#define ENUM_CLASS_DECLARE(cls_type, enum_type) /
public: enum_type m_val; /
public: /
cls_type ( const enum_type& s): m_val(s) {} ; /
bool operator == ( const enum_type& cs ) { /
if ( m_val == m_val ) return true; /
else return false; } /
operator enum_type() { return m_val; };
这样,上文的两个状态枚举类可以简化成下面的两个样子:
class ComputerState
{
public:
enum _ComputerState
{
stateOpen,
stateClosed,
stateSuspended
};
ENUM_CLASS_DECLARE(ComputerState, _ComputerState)
};
class SpeakerState
{
public:
enum _SpeakerState
{
stateOpen,
stateClosed
};
ENUM_CLASS_DECLARE(SpeakerState, _SpeakerState)
};
到此为止,目的只是为了解决由于C++中枚举类型的成员变量的全局唯一性引起的在成员命名时的苦恼,一个简单的OPEN状态可能会用在许多不同的设备或其他多种事物对象的状态枚举中,解决此问题,其一就是一个OPEN状态对于不同的设备使用不同的名称,比如ComputerOpen、SpeakerOpen,其二是创建一个硕大无比的Enum类型,包含软件中涉及到的所有设备所有事物对象的状态,其三就是本文所说的枚举类型的类封装。
C++语言中,对于一个枚举类型(enum),其成员值在所属枚举类型的声明作用域内是不可重复的。这个继承自C语言的特性,使我在写程序时碰到有相同名称的枚举成员时,苦于寻找且方便易读的替代枚举名称。
这在C++程序开发方面带来了许多的不方便,在涉及枚举类型时必须时刻关注与现有的枚举变量是否有重名,在一定程度上限制了命名的自主性,也会降低程序的可读性。而在Visual Basic 6和.net系列语言中,两个不同的Enum类型可以具有相同的成员,在使用时只需加上Enum类型名称。目前就是要在C++中实现这种功能。
一个例子,用以描述一台计算机和一个音箱的类,它们都有一个状态属性State。音箱状态值只有开和关两种,而计算机状态还有休眠状态。由于休眠对于音箱没有任何意义,在严格要求的编码下,对于向音箱赋上休眠状态的无意义举动必须在编译时阻止,因此需在使此两种设备类的状态属性分别两个状态枚举类型,计算机状态和音箱状态,代码如下:
上述代码在编译时就不能通过,因为两个枚举的成员都是全局的,stateOpen和stateClosed都重复出现。因此,现在需要做的就是将这两个状态枚举类型分在两个作用域中声明,可采用的方式是在不同的namespace中声明或在不同的类中声明。
enum ComputerState
{
stateOpen,
stateClosed,
stateSuspended
};
enum SpeakerState
{
stateOpen,
stateClosed
};
class Computer
{
public:
void SetState(ComputerState s) { ... }
};
在不同名称空间中声明枚举的代码如下:
namespace computer
{
enum ComputerState
{
stateOpen,
stateClosed,
stateSuspended
};
};
namespace speaker
{
enum SpeakerState
{
stateOpen,
stateClosed
};
};
using namespace computer;
using namespace speaker;
class Computer
{
public:
void SetState(ComputerState s)
{
if ( s == computer::stateOpen ) printf("State set to Open
");
else if ( s == computer::stateClosed ) printf("State set to Closed
");
else if ( s == computer::stateSuspended )
printf("State set to Suspended
");
}
};
虽然代码编译运行都通过,但在不同的名称空间中声明显然不是个好办法,一是Computer::SetState()方法中状态判断是,状态值(stateOpen等)前面并不是类型名称而是namespace名称。这样在代码可读性方面还是比较差。第二,就是有多少个enum类型,就得用多少个namespace以及using namespace,这在实际使用中是无法忍受的。因此, 目前只能是在class中声明enum类,将enum类型class化。代码修改如下:
class ComputerState
{
public:
enum _ComputerState
{
stateOpen,
stateClosed,
stateSuspended
};
};
class SpeakerState
{
public:
enum _SpeakerState
{
stateOpen,
stateClosed
};
};
class Computer
{
public:
void SetState(ComputerState::_ComputerState s)
{
if ( s == ComputerState::stateOpen )
printf("State set to Open
");
else if ( s == ComputerState::stateClosed )
printf("State set to Closed
");
else if ( s == ComputerState::stateSuspended )
printf("State set to Suspended
");
}
};
上述的每个Enum的作用域限制在一个类中,这样实现了不同enum类型其成员的重,但在使用时的类型表述上还没有统一。因此,根据枚举类型变量常用的几个操作符,对其做重载。代码如下:
class ComputerState
{
public:
enum _ComputerState
{
stateOpen,
stateClosed,
stateSuspended
};
private:
_ComputerState m_val;
public:
ComputerState(): m_val(stateOpen) {};
ComputerState (const _ComputerState& s): m_val(s) { };
bool operator == ( const ComputerState& cs )
{
if ( m_val == cs.m_val ) return true;
else return false;
}
operator _ComputerState() { return m_val; }
};
class SpeakerState
{
public:
enum _SpeakerState
{
stateOpen,
stateClosed
};
private:
_SpeakerState m_val;
public:
SpeakerState(): m_val(stateOpen) {};
SpeakerState (const _SpeakerState& s): m_val(s) { };
bool operator == ( const SpeakerState& cs )
{
if ( m_val == cs.m_val ) return true;
else return false;
}
operator _ComputerState() { return m_val; }
};
上述代码增加了类型值成员变量m_val、类复制构造函数,重载了枚举类的等于比较操作符和类型解包操作符,从而实现了一个枚举类型的类化,实现了枚举成员与枚举类自动组包和解包,在使用上,枚举的使用和VB里面除了"."与"::"在操作符上语言本身的区别外,基本相同。最重要的是在枚举成员在命名时不必因为有重名而使用可读性差的或者增加不必要的区别符号或名称。上述枚举类的使用时代码示例如下
class Computer
{
public:
void SetState(ComputerState s)
{
if ( s == ComputerState::stateOpen ) printf("State set to Open
");
else if ( s == ComputerState::stateClosed ) printf("State set to Closed
");
else if ( s == ComputerState::stateSuspended )
printf("State set to Suspended
");
}
};
class Speaker
{
public:
void SetState(SpeakerState s)
{
if ( s == SpeakerState::stateOpen ) printf("State set to Open
");
else if ( s == SpeakerState::stateClosed ) printf("State set to Closed
");
}
};
int main(int argc, char *argv[])
{
Computer cpt;
Speaker spk;
ComputerState cs = ComputerState::stateClosed;
SpeakerState ss = SpeakerState::stateOpen;
cpt.SetState( ComputerState::stateOpen );
spk.SetState( SpeakerState::stateOpen );
cpt.SetState( cs );
spk.SetState( ss );
return EXIT_SUCCESS;
}
但是,由于enum的封装时增加了额外的构造函数和重载操作符,这部分代码将增加不少的工作量。为了减少这部分工作量,可以将这部分增加的函数定义成宏,如下:
#define ENUM_CLASS_DECLARE(cls_type, enum_type) /
public: enum_type m_val; /
public: /
cls_type ( const enum_type& s): m_val(s) {} ; /
bool operator == ( const enum_type& cs ) { /
if ( m_val == m_val ) return true; /
else return false; } /
operator enum_type() { return m_val; };
这样,上文的两个状态枚举类可以简化成下面的两个样子:
class ComputerState
{
public:
enum _ComputerState
{
stateOpen,
stateClosed,
stateSuspended
};
ENUM_CLASS_DECLARE(ComputerState, _ComputerState)
};
class SpeakerState
{
public:
enum _SpeakerState
{
stateOpen,
stateClosed
};
ENUM_CLASS_DECLARE(SpeakerState, _SpeakerState)
};
到此为止,目的只是为了解决由于C++中枚举类型的成员变量的全局唯一性引起的在成员命名时的苦恼,一个简单的OPEN状态可能会用在许多不同的设备或其他多种事物对象的状态枚举中,解决此问题,其一就是一个OPEN状态对于不同的设备使用不同的名称,比如ComputerOpen、SpeakerOpen,其二是创建一个硕大无比的Enum类型,包含软件中涉及到的所有设备所有事物对象的状态,其三就是本文所说的枚举类型的类封装。
相关文章推荐
- C++中enum枚举类型成员重名问题的解决方法 - Enum枚举类型的类封装(转)
- C++中enum枚举类型成员重名问题的解决方法 - Enum枚举类型的类封装(转)
- 【转】C++中enum枚举类型成员重名问题的解决方法 - Enum枚举类型的类封装
- C++中enum枚举类型成员重名问题的解决方法 - Enum枚举类型的类封装
- C++中enum枚举类型成员重名问题的解决方法 - Enum枚举类型的类封装
- C++中enum枚举类型成员重名问题的解决方法 - Enum枚举类型的类封装
- 【C++】Accessor and Mutator Functions & 函数形参与类私有成员重名的解决方法
- MFC之头文件相互包含问题及解决方法 error C4430: 缺少类型说明符 - 假定为 int。注意: C++ 不支持默认 int
- C++库研究笔记——使用函数模板还是类模板?+ 一个类型重复问题的两种解决方法
- C++ 使用#define带来的问题及解决方法(const enum inline)
- C++模板函数中含有数据类型成员时导致编译错误(显示未知类型)的解决方法
- 使用Navicat Premium将Oracle数据库中的表和数据迁移到MySQL数据库中,遇到的Date类型出现精度问题及解决方法
- JAVA泛型-类型擦除太恶心,但项目中大量使用,以及类型擦除引起的问题及解决方法
- CSDN博客中C++相关代码出现 <span style="white-space:pre"> </span> 乱码问题解决方法
- java中解决构造函数中成员变量和形参重名的问题
- Exchange 2010 添加DAG成员报静态地址配置错误问题解决方法
- C++ 学习笔记(19)new/delete表达式、定位new、typeid、dynamic_cast、type_info、枚举类型、成员函数指针、union、位域、volatile限定符、链接指示
- Linq查询出现"此上下文仅支持基元类型或枚举类型。"解决方法
- error C4430: 缺少类型说明符 - 假定为 int。注意: C++ 不支持默认 int 错误的解决方法
- java基本类型作为类成员和方法成员时默认值问题