C++ 避免复制开关状态

C++ 避免复制开关状态,c++,switch-statement,boilerplate,C++,Switch Statement,Boilerplate,可以重构此代码以避免复制switch语句吗 enum class Animal { Cat, Dog, Fish}; float GetMaxSpeed(Animal a) { switch (a) { case Animal::Cat: return 30; case Animal::Dog: return 40; case Animal::Fish: retur

可以重构此代码以避免复制switch语句吗

enum class Animal
{ Cat, Dog, Fish};

float GetMaxSpeed(Animal a)
{
 switch (a)
    {
        case Animal::Cat:
            return 30;
        case Animal::Dog:
            return 40;
        case Animal::Fish:
            return 15;
    }
 }

string GetGermanTranslation(Animal a)
{
 switch (a)
    {
        case Animal::Cat:
            return "Katze";
        case Animal::Dog:
            return "Hund";
        case Animal::Fish:
            return "Fische";
    }
 }

显然,这是一个玩具示例,我真正的枚举类要大得多。

更面向对象的方法是依赖多态性,而不是连续打开表示类型的枚举数值

要遵循此方法,首先定义一个抽象类,
Animal
,该类指定其子类应实现的成员函数:

class Animal {
public:
    virtual std::string GetGermanTranslation() const = 0;
    virtual float GetMaxSpeed() const = 0;
    virtual ~Animal() = default;
};
然后,公开从此类派生并重写虚拟成员函数
GetGermanTranslation()
GetMaxSpeed()

例如,对于
Cat

class Cat: public Animal {
public:
   std::string GetGermanTranslation() const override { return "Katze"; };
   float GetMaxSpeed() const override  { return 30; };
};
然后,类似地,对于

class Dog: public Animal {
public:
   std::string GetGermanTranslation() const override { return "Hund"; };
   float GetMaxSpeed() const override  { return 40; };
};
您可以类似地定义
Fish

最后,有一个指向
动物
对象的指针或引用,只需调用相应的虚拟成员函数:

void displayAnimal(const Animal& animal) {
   std::cout << "The " << animal.GetGermanTranslation();
   std::cout << " runs at " << animal.GetMaxSpeed() << '\n';
}

如果不另行指定,则枚举类型中的第一个枚举数的值为0,后续枚举数的值比前一个枚举数的值大一个。所以

enum Animal
{ Cat, Dog, Fish};
Cat
的值为0,
Dog
的值为1,
Fish
的值为2。要将这些值映射到其他值集,只需将它们用作数组索引:

int max_speed[] = {
    30, 40, 15
};

const char* german_name[] = {
    "Katze",
    "Hund",
    "Fische"
};
现在,您可以编写诸如
max\u speed[Cat]
德语名称[Dog]
之类的内容


请注意,字符串文本位于双引号内,例如,
“Katze”
,而不是问题中的单引号。围绕多个字符的单引号创建了一个称为“多字符文字”的时髦东西。它们几乎毫无用处。

似乎很简单。根据枚举值的数量,是否尝试简单地使用映射或数组枚举枚举枚举值,并给出相应的速度和转换?或者,如果保证枚举值在数值上是连续的,则使用两者的简单数组?不需要任何开关语句。考虑使用不同的方法:<代码> const动物数据MIATALDATABOR[] = {{动物::猫,30,“Katze”},{动物::40,“Hund”},{动物::鱼,15,“FISCHE”};<代码> >不幸的是C++不支持指定的初始化语法,<代码> [动物::猫] = { 30,“Katze”} /代码> @ USE253551。你能详细说明这个吗?最好是回答。@ SavValavik谢谢,这也是非常有用的。如果没有直接映射,例如最大速度未知,有什么解决方案吗?可以使用映射(
std::map
)来过滤稀疏索引,但这似乎是一种过度使用。对于某些情况下可能缺少的功能,可以使用
std::optional
。或者您可以使用
std::bitset
来跟踪现有的功能。这太过分了。我举了一个例子,说明如何不这样做。这种开关非常简单、快速,并且易于维护。而且你的解是正交的;OP具有枚举值而不是事物的实例。@swiths此方法遵循,而
开关不遵循。例如,假设您必须使用鼠标动物扩展动物:使用OOP方法,您只需创建一个新类
mouse
,该类派生自
animal
,并重写相应的成员函数。另一方面,使用
switch
方法,您必须遍历整个代码,查找所有
switch
语句,并为每个switch语句添加一个新的大小写。多态方法可以在不修改现有代码的情况下进行扩展,然而,基于
switch
语句的方法需要修改现有代码以进行扩展。后者不仅要做更多的工作,而且更容易出错。它也不太本地化,并且在整个代码中传播。不正确。编译器警告交换机中缺少枚举。这是一项非常非常小的工作。这是一个非常有用的问题,但在我的现实世界中,我希望在枚举及其属性之间有明确的、可读的映射。
int max_speed[] = {
    30, 40, 15
};

const char* german_name[] = {
    "Katze",
    "Hund",
    "Fische"
};