cpp中模仿枚举继承的解决方案

Ary*_*ian 5 c++ inheritance enums

我知道 enum 继承在 c++ 中是不可能的,但我正在寻找可以简单地解决我的情况的特定数据结构。假设我有这两个枚举:

    enum Fruit { apple, orange};
    enum Drink { water, milk};
Run Code Online (Sandbox Code Playgroud)

我想要这两个的父级,我可以在这个抽象方法中用作参数

   void LetsEat(Eatable eatable){}
Run Code Online (Sandbox Code Playgroud)

它们将用作简单的开关,基本上我想保持我的代码干净和类型安全。我想知道我是否会被迫使用需要初始化的继承类。对于这个简单的问题来说太过分了。

Sil*_*olo 7

这听起来像是std::variant.

#include <variant>
#include <iostream>

// Define our enums
enum Fruit { Apple, Orange };
enum Drink { Water, Milk };

// An Eatable is either a Fruit or a Drink
using Eatable = std::variant<Fruit, Drink>;

void letsEat(Eatable eatable) {
  // We can use the index() method to figure out which one we have
  switch (eatable.index()) {
  case 0:
    std::cout << "It's a Fruit!" << std::endl;
    break;
  case 1:
    std::cout << "It's a Drink!" << std::endl;
    break;
  }
}

int main() {
  letsEat(Apple);
  letsEat(Water);
}
Run Code Online (Sandbox Code Playgroud)

请注意std::variant<Fruit, Drink>,严格来说,这不是Fruitor的超类型Drink。相反,它完全是一个新类型,但我们通过它的构造函数获得了从FruitDrink 到的 隐式转换std::variant<Fruit, Drink>

如果您不使用 C++17,则可以使用boost::variantBoost C++ 库。


Sam*_*hik 6

很笼统地说,enums只是装扮ints。

enum Fruit { apple, orange};
Run Code Online (Sandbox Code Playgroud)

如果查看编译后的代码,您会发现 an applewill 由值 0 表示,an orangewill 由值 1 表示。

enum Drink { water, milk};
Run Code Online (Sandbox Code Playgroud)

同样的事情也会在这里发生。water将用值 0 表示,milk将用值 1 表示。您可以从这里开始看到明显的问题。

一,稍微原始的解决方案相当于在瓷器店里放牛:

enum Drink { water=2, milk=3};
Run Code Online (Sandbox Code Playgroud)

现在你可以在你传递一个int值的地方做一些事情,并通过它的值弄清楚到底传递了什么。

但这可能需要大量丑陋的演员阵容,无处不在。生成的代码如果发布到 Stackoverflow,可能会吸引反对票。

否决票将是因为在现代的 C++17 后世界中有更干净的解决方案可用。首先,您可以切换到enum课程。

enum class Fruit { apple, orange};
enum class Drink { water, milk};
Run Code Online (Sandbox Code Playgroud)

这获得了额外的类型安全性。将 a 分配给 a 不再那么容易FruitDrink。您的 C++ 编译器会在很多情况下发出警告,声音很大。您的 C++ 编译器将帮助您在代码中找到更多错误。确实,这将需要更多的输入。您将始终必须在任何地方指定具有完整限定的枚举值,即Fruit::appleand Drink::water,当在现有代码中仅使用appleandwater就足够了。但是一些额外的类型字符对于更多类型安全的代码来说是一个很小的代价,并且能够简单地声明:

typedef std::variant<Fruit, Drink> Eatable;
Run Code Online (Sandbox Code Playgroud)

简单地做你一直想做的事情:

void LetsEat(Eatable eatable){}
Run Code Online (Sandbox Code Playgroud)

一切都会如您所愿。LetsEat将接受 aFruit或 aDrink作为其参数。它必须做更多的工作,才能弄清楚std::variant.

std::variant是 C++ 库中更复杂的模板之一,无法在 Stackoverflow 上的一两短段落中完整地解释如何使用它。但这是可能的,我将向您推荐您的 C++ 教科书,以获取有关如何使用此模板的完整说明。