我有一个有两个值的枚举类,我想创建一个接收值的方法 然后返回另一个。我还想维护类型安全(这就是为什么我使用枚举类而不是enum)。
http://www.cplusplus.com/doc/tutorial/other_data_types/没有提到任何关于方法的内容 然而,在我的印象中,任何类型的类都可以有方法。
我有一个有两个值的枚举类,我想创建一个接收值的方法 然后返回另一个。我还想维护类型安全(这就是为什么我使用枚举类而不是enum)。
http://www.cplusplus.com/doc/tutorial/other_data_types/没有提到任何关于方法的内容 然而,在我的印象中,任何类型的类都可以有方法。
当前回答
虽然“你不能”这个答案在技术上是正确的,但我相信你可以用下面的想法来实现你想要的行为:
我猜你想写这样的东西:
Fruit f = Fruit::Strawberry;
f.IsYellow();
你希望代码看起来像这样:
enum class Fruit : uint8_t
{
Apple,
Pear,
Banana,
Strawberry,
bool IsYellow() { return this == Banana; }
};
但是,当然,它不起作用,因为枚举不能有方法(并且'this'在上面的上下文中没有任何意义)
但是,如果您使用包含非类枚举和包含该类型值的单个成员变量的普通类的思想,则可以非常接近您想要的语法/行为/类型安全。例如:
class Fruit
{
public:
enum Value : uint8_t
{
Apple,
Pear,
Banana,
Strawberry
};
Fruit() = default;
constexpr Fruit(Value aFruit) : value(aFruit) { }
#if Enable switch(fruit) use case:
// Allow switch and comparisons.
constexpr operator Value() const { return value; }
// Prevent usage: if(fruit)
explicit operator bool() const = delete;
#else
constexpr bool operator==(Fruit a) const { return value == a.value; }
constexpr bool operator!=(Fruit a) const { return value != a.value; }
#endif
constexpr bool IsYellow() const { return value == Banana; }
private:
Value value;
};
现在你可以这样写:
Fruit f = Fruit::Strawberry;
f.IsYellow();
编译器会阻止如下事情:
Fruit f = 1; // Compile time error.
你可以很容易地添加这样的方法:
Fruit f("Apple");
and
f.ToString();
可支持。
其他回答
不,他们不能。
我可以理解c++ 11中强类型枚举的枚举类部分似乎暗示你的枚举也有类特征,但事实并非如此。我有根据的猜测是,关键字的选择受到了我们在c++ 11之前使用的获取范围枚举的模式的启发:
class Foo {
public:
enum {BAR, BAZ};
};
然而,这只是语法。同样,枚举类不是类。
正如在另一个答案中提到的,没有。甚至枚举类也不是一个类。
通常需要枚举方法的原因是,它不是一个常规的(只是递增的)枚举,而是一种按位定义要掩盖的值或需要其他位算术操作:
enum class Flags : unsigned char {
Flag1 = 0x01 , // Bit #0
Flag2 = 0x02 , // Bit #1
Flag3 = 0x04 , // Bit #3
// aso ...
}
// Sets both lower bits
unsigned char flags = (unsigned char)(Flags::Flag1 | Flags::Flag2);
// Set Flag3
flags |= Flags::Flag3;
// Reset Flag2
flags &= ~Flags::Flag2;
显然,人们会考虑封装必要的操作来重新/设置单个/组位,例如位掩码值,甚至位索引驱动的操作对于操作这样一组“标志”是有用的。
c++11结构/类规范只是支持更好的枚举值访问范围。不多不少!
摆脱不能为枚举(类)声明方法的限制的方法是,使用std::bitset(包装类)或位域联合。
联合,这样的位域联合可以有方法(请看这里的限制!)。
我有一个示例,如何将位掩码值(如上所示)转换为相应的位索引,可以沿着std::bitset在这里使用:BitIndexConverter.hpp 我发现这对于提高一些基于“旗帜”决策的算法的可读性非常有用。
把注意力集中在问题的描述上,而不是标题,一个可能的答案是
struct LowLevelMouseEvent {
enum Enum {
mouse_event_uninitialized = -2000000000, // generate crash if try to use it uninitialized.
mouse_event_unknown = 0,
mouse_event_unimplemented,
mouse_event_unnecessary,
mouse_event_move,
mouse_event_left_down,
mouse_event_left_up,
mouse_event_right_down,
mouse_event_right_up,
mouse_event_middle_down,
mouse_event_middle_up,
mouse_event_wheel
};
static const char* ToStr (const type::LowLevelMouseEvent::Enum& event)
{
switch (event) {
case mouse_event_unknown: return "unknown";
case mouse_event_unimplemented: return "unimplemented";
case mouse_event_unnecessary: return "unnecessary";
case mouse_event_move: return "move";
case mouse_event_left_down: return "left down";
case mouse_event_left_up: return "left up";
case mouse_event_right_down: return "right down";
case mouse_event_right_up: return "right up";
case mouse_event_middle_down: return "middle down";
case mouse_event_middle_up: return "middle up";
case mouse_event_wheel: return "wheel";
default:
Assert (false);
break;
}
return "";
}
};
是的,它们可以,但是你需要创建一个包装器类,例如:
#include <iostream>
using namespace std;
class Selection {
public:
enum SelectionEnum {
yes,
maybe,
iDontKnow,
canYouRepeatTheQuestion
};
Selection(SelectionEnum selection){value=selection;};
string toString() {
string selectionToString[4]={
"Yes",
"Maybe",
"I don't know",
"Can you repeat the question?"
};
return selectionToString[value];
};
private:
SelectionEnum value;
};
int main(){
Selection s=Selection(Selection::yes);
cout<<s.toString()<<endl;
return 0;
}
虽然“你不能”这个答案在技术上是正确的,但我相信你可以用下面的想法来实现你想要的行为:
我猜你想写这样的东西:
Fruit f = Fruit::Strawberry;
f.IsYellow();
你希望代码看起来像这样:
enum class Fruit : uint8_t
{
Apple,
Pear,
Banana,
Strawberry,
bool IsYellow() { return this == Banana; }
};
但是,当然,它不起作用,因为枚举不能有方法(并且'this'在上面的上下文中没有任何意义)
但是,如果您使用包含非类枚举和包含该类型值的单个成员变量的普通类的思想,则可以非常接近您想要的语法/行为/类型安全。例如:
class Fruit
{
public:
enum Value : uint8_t
{
Apple,
Pear,
Banana,
Strawberry
};
Fruit() = default;
constexpr Fruit(Value aFruit) : value(aFruit) { }
#if Enable switch(fruit) use case:
// Allow switch and comparisons.
constexpr operator Value() const { return value; }
// Prevent usage: if(fruit)
explicit operator bool() const = delete;
#else
constexpr bool operator==(Fruit a) const { return value == a.value; }
constexpr bool operator!=(Fruit a) const { return value != a.value; }
#endif
constexpr bool IsYellow() const { return value == Banana; }
private:
Value value;
};
现在你可以这样写:
Fruit f = Fruit::Strawberry;
f.IsYellow();
编译器会阻止如下事情:
Fruit f = 1; // Compile time error.
你可以很容易地添加这样的方法:
Fruit f("Apple");
and
f.ToString();
可支持。