我有一个有两个值的枚举类,我想创建一个接收值的方法 然后返回另一个。我还想维护类型安全(这就是为什么我使用枚举类而不是enum)。
http://www.cplusplus.com/doc/tutorial/other_data_types/没有提到任何关于方法的内容 然而,在我的印象中,任何类型的类都可以有方法。
我有一个有两个值的枚举类,我想创建一个接收值的方法 然后返回另一个。我还想维护类型安全(这就是为什么我使用枚举类而不是enum)。
http://www.cplusplus.com/doc/tutorial/other_data_types/没有提到任何关于方法的内容 然而,在我的印象中,任何类型的类都可以有方法。
当前回答
根据jtlim的回答
想法(解决方案)
enum ErrorType: int {
noConnection,
noMemory
};
class Error {
public:
Error() = default;
constexpr Error(ErrorType type) : type(type) { }
operator ErrorType() const { return type; }
constexpr bool operator == (Error error) const { return type == error.type; }
constexpr bool operator != (Error error) const { return type != error.type; }
constexpr bool operator == (ErrorType errorType) const { return type == errorType; }
constexpr bool operator != (ErrorType errorType) const { return type != errorType; }
String description() {
switch (type) {
case noConnection: return "no connection";
case noMemory: return "no memory";
default: return "undefined error";
}
}
private:
ErrorType type;
};
使用
Error err = Error(noConnection);
err = noMemory;
print("1 " + err.description());
switch (err) {
case noConnection:
print("2 bad connection");
break;
case noMemory:
print("2 disk is full");
break;
default:
print("2 oops");
break;
}
if (err == noMemory) { print("3 Errors match"); }
if (err != noConnection) { print("4 Errors don't match"); }
其他回答
虽然“你不能”这个答案在技术上是正确的,但我相信你可以用下面的想法来实现你想要的行为:
我猜你想写这样的东西:
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();
可支持。
它可能不能满足您的所有需求,但使用非成员操作符仍然可以获得很多乐趣。例如:
#include <iostream>
enum class security_level
{
none, low, medium, high
};
static bool operator!(security_level s) { return s == security_level::none; }
static security_level& operator++(security_level& s)
{
switch(s)
{
case security_level::none: s = security_level::low; break;
case security_level::low: s = security_level::medium; break;
case security_level::medium: s = security_level::high; break;
case security_level::high: break;
}
return s;
}
static std::ostream & operator<<(std::ostream &o, security_level s)
{
switch(s)
{
case security_level::none: return o << "none";
case security_level::low: return o << "low";
case security_level::medium: return o << "medium";
case security_level::high: return o << "high";
}
}
这允许如下代码
security_level l = security_level::none;
if(!!l) { std::cout << "has a security level: " << l << std::endl; } // not reached
++++l;
if(!!l) { std::cout << "has a security level: " << l << std::endl; } // reached: "medium"
有一种非常兼容的能力(§),可以将枚举重构为类,而无需重写代码,这意味着你可以有效地完成你要求做的事情,而无需进行太多的编辑。
(§)正如ElementW在评论中指出的那样,依赖类型特征的代码将无法工作,因此,例如不能使用auto等。可能有一些方法可以处理这些东西,但最终是将枚举转换为类,而颠覆c++总是错误的
枚举结构体和枚举类规范是关于作用域的,所以不是这个的一部分。
您的原始枚举是:“pet”(这只是一个例子!)
enum pet {
fish, cat, dog, bird, rabbit, other
};
(1)将其修改为eg petEnum(以便在现有代码中隐藏它)。
enum petEnum {
fish, cat, dog, bird, rabbit, other
};
在它下面添加一个新的类声明(用原来的enum命名)
class pet {
private:
petEnum value;
pet() {}
public:
pet(const petEnum& v) : value{v} {} //not explicit here.
operator petEnum() const { return value; }
pet& operator=(petEnum v) { value = v; return *this;}
bool operator==(const petEnum v) const { return value == v; }
bool operator!=(const petEnum v) const { return value != v; }
// operator std::string() const;
};
你现在可以添加任何你喜欢的类方法到你的宠物类。 如。字符串操作符
pet::operator std::string() const {
switch (value) {
case fish: return "fish";
case cat: return "cat";
case dog: return "dog";
case bird: return "bird";
case rabbit: return "rabbit";
case other: return "Wow. How exotic of you!";
}
}
现在你可以使用std::cout…
int main() {
pet myPet = rabbit;
if(myPet != fish) {
cout << "No splashing! ";
}
std::cout << "I have a " << std::string(myPet) << std::endl;
return 0;
}
根据jtlim的回答
想法(解决方案)
enum ErrorType: int {
noConnection,
noMemory
};
class Error {
public:
Error() = default;
constexpr Error(ErrorType type) : type(type) { }
operator ErrorType() const { return type; }
constexpr bool operator == (Error error) const { return type == error.type; }
constexpr bool operator != (Error error) const { return type != error.type; }
constexpr bool operator == (ErrorType errorType) const { return type == errorType; }
constexpr bool operator != (ErrorType errorType) const { return type != errorType; }
String description() {
switch (type) {
case noConnection: return "no connection";
case noMemory: return "no memory";
default: return "undefined error";
}
}
private:
ErrorType type;
};
使用
Error err = Error(noConnection);
err = noMemory;
print("1 " + err.description());
switch (err) {
case noConnection:
print("2 bad connection");
break;
case noMemory:
print("2 disk is full");
break;
default:
print("2 oops");
break;
}
if (err == noMemory) { print("3 Errors match"); }
if (err != noConnection) { print("4 Errors don't match"); }
是的,它们可以,但是你需要创建一个包装器类,例如:
#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;
}