C ++中有没有一种方法可以扩展/“继承”枚举?
IE浏览器:
enum Enum {A,B,C};
enum EnumEx : public Enum {D,E,F};
或至少定义它们之间的转换?
C ++中有没有一种方法可以扩展/“继承”枚举?
IE浏览器:
enum Enum {A,B,C};
enum EnumEx : public Enum {D,E,F};
或至少定义它们之间的转换?
Answers:
不,那里没有。
enum
在C ++中确实是可怜的事情,这当然是不幸的。
甚至class enum
C ++ 0x中引入的方法也不能解决此可扩展性问题(尽管它们至少在类型安全方面做了一些工作)。
它们的唯一优点enum
是它们不存在:它们提供了一些类型安全性,同时不增加任何运行时开销,因为它们直接由编译器替换。
如果您想要这样的野兽,则必须自己动手:
MyEnum
,其中包含一个int(基本上)您现在可以随意扩展您的类(添加命名构造函数)...
不过,这是一种解决方法,我从未找到过令人满意的处理枚举的方法...
我已经通过这种方式解决了:
typedef enum
{
#include "NetProtocols.def"
} eNetProtocols, eNP;
当然,如果在NetProtocols.def文件中添加新的网络协议,则必须重新编译,但至少它是可扩展的。
如果您能够创建枚举的子类,则必须采用其他方法。
子类中的实例集是超类中的实例的子集。考虑一下标准的“形状”示例。Shape类代表所有Shape的集合。Circle类及其子类表示Shapes的子集,这些Shapes是Circles。
为了保持一致,枚举的子类必须包含其继承的枚举中元素的子集。
(不,C ++不支持此功能。)
enum A {1, 65525};
,编译器决定使用16位无符号int表示它。现在假设我定义了enumEx : public Enum { 131071 };
。不能将EnumEx类型的对象作为Enum的实例传递,实际上将对其进行切片。哎呀。这就是为什么您需要C ++中的指针来执行运行时多态性的原因。我想C ++可以使每个枚举都成为最大的枚举的大小。但是从概念上讲,值131071不应是Enum的有效实例。
在我设计的小型硬件设备上运行的某些项目中,我遇到了这个问题。有一个包含许多服务的通用项目。其中一些服务使用枚举作为参数来获得附加的类型检查和安全性。我需要能够在使用这些服务的项目中扩展这些枚举。
正如其他人提到的,c ++不允许您扩展枚举。但是,您可以使用具有enum class的所有优点的名称空间和模板来模拟enum。
枚举类具有以下优点:
现在,如果将一个类定义为枚举,则无法在类声明中创建该枚举的constexpr实例,因为该类尚未完成,并且会导致编译错误。同样,即使这可行,您以后也无法在另一个文件/子项目中轻松扩展枚举的值集。
现在,名称空间没有这种问题,但是它们不提供类型安全性。
答案是首先创建一个模板化的基类,该基类允许不同基数的枚举,这样我们就不会浪费我们不使用的东西。
template <typename TYPE>
class EnumClass {
private:
TYPE value_;
public:
explicit constexpr EnumClass(TYPE value) :
value_(value){
}
constexpr EnumClass() = default;
~EnumClass() = default;
constexpr explicit EnumClass(const EnumClass &) = default;
constexpr EnumClass &operator=(const EnumClass &) = default;
constexpr operator TYPE() const {return value_;}
constexpr TYPE value() const {return value_;}
};
然后,对于每个要扩展和模拟的枚举类,我们创建一个名称空间和一个Type,如下所示:
namespace EnumName {
class Type :public Enum<uint8_t> {
public:
explicit constexpr Type(uint8_t value): Enum<uint8_t>(value){}
constexpr Enum() = default;
}
constexpr auto Value1 = Type(1);
constexpr auto Value2 = Type(2);
constexpr auto Value3 = Type(3);
}
然后,在代码中,如果以后包含原始EnumName,则可以执行以下操作:
namespace EnumName {
constexpr auto Value4 = Type(4U);
constexpr auto Value5 = Type(5U);
constexpr auto Value6 = Type(6U);
constexpr std::array<Type, 6U> Set = {Value1, Value2, Value3, Value4, Value5, Value6};
}
现在您可以 像这样使用枚举:
#include <iostream>
void fn(EnumName::Type val){
if( val != EnumName::Value1 ){
std::cout << val;
}
}
int main(){
for( auto e :EnumName::Set){
switch(e){
case EnumName::Value1:
std::cout << "a";
break;
case EnumName::Value4:
std::cout << "b";
break;
default:
fn(e);
}
}
}
因此,我们有一个案例说明,枚举比较,参数类型安全性及其所有可扩展性。请注意,该集合是constexpr,不会最终在小型微型计算机上使用宝贵的RAM(在Godbolt.org上验证过的位置。:-)。作为奖励,我们可以迭代一组枚举值。
实际上,您可以以某种方式扩展枚举。
C ++标准将有效的枚举值定义为基础类型的所有有效值,因此以下是有效的C ++(11+)。它不是不确定的行为,但是非常讨厌-您已经被警告。
#include <cstdint>
enum Test1:unit8_t {
Value1 =0,
Value2 =1
};
constexpr auto Value3 = static_cast<Test1>(3);
constexpr auto Value4 = static_cast<Test1>(4);
constexpr auto Value5 = static_cast<Test1>(5);
Test1 fn(Test1 val){
switch(val){
case Value1:
case Value2:
case Value3:
case Value4:
return Value1;
case Value5:
return Value5;
}
}
int main(){
return static_cast<uint8_t>(fn(Value5));
}
请注意,大多数编译器在生成关于switch语句中缺少枚举值的警告时不会将附加值视为集合的一部分,因此clang和gcc将在缺少Value2时发出警告,但在上述Value4缺失时将不执行任何操作切换语句。
我这样做
'''
enum OPC_t // frame Operation Codes
{
OPC_CVSND = 0 // Send CV value
, OPC_CVREQ = 1 // Request CV (only valid for master app)
, OPC_COMND = 2 // Command
, OPC_HRTBT = 3 // Heart Beat
};
enum rxStatus_t // this extends OPC_t
{
RX_CVSND = OPC_CVSND // Send CV value
, RX_CVREQ = OPC_CVREQ // Request CV
, RX_COMND = OPC_COMND // Command
, RX_HRTBT = OPC_HRTBT // Heart Beat
, RX_NONE // No new Rx
, RX_NEWCHIP // new chip detected
};
''''
以下代码运行良好。
enum Enum {A,B,C};
enum EnumEx {D=C+1,E,F};