【问题标题】:C++11: How to create an enum class inside an class that behaves like a sub class?C++11:如何在行为类似于子类的类中创建枚举类?
【发布时间】:2019-02-21 10:33:45
【问题描述】:

为了解释我的问题,我在下面发布了一个示例。这种形式的代码未经测试,因此可能存在一些语法错误。由于我必须使用集成电路中的许多寄存器,它们的地址可以重新映射,因此创建如下所示的结构将非常有用。创建这些结构有什么技巧吗?由于此示例无法按我想要的方式工作,因为 foo 需要 Country 对象,并且 Country::Europe::Italy 作为参数无效。

// I want to create a structure like this
class myClass {
public:
    class Country {

        enum class Europe {
            England,
            France,
            Germany,
            Italy
        };

        enum class Asia {
            China,
            Japan
        };

    };

    // Here I want to make sure, that the method is only
    // called with a Country element and e.g. Italy should
    // behave like a Country object. Actually it should behave
    // as if it is derived from Country.
    int foo(Country c);

};



int main() {
    myClass myC();

    // Exemplary call of the method foo
    myC.foo(myClass::Country::Europe::Italy);
}

【问题讨论】:

  • enum Class 不是一个类。所以不能从Country类派生出来。

标签: class c++11 data-structures struct enums


【解决方案1】:

您不能使用enum class 来实现您的目标。但是,您可以将 namespace 与一组硬编码的 constexpr 对象一起使用:

struct Country 
{ 
    int _id; 
};

namespace Countries
{ 
    namespace Europe 
    {
        constexpr Country Italy{0};
        constexpr Country France{1};
    };
};

用法:

myC.foo(Countries::Europe::Italy);

【讨论】:

  • 您实际上可以在 c++17 中使用枚举而不是 struct Country 来做到这一点
【解决方案2】:

使用寄存器的适当示例和更好的解释会更好。我猜你想从一个寄存器名重新映射到另一个。一条建议:

class Register {
public:
  enum class UserName {
    REG_IO0,
    REG_MEM1
  };
  enum class CPUName {
    REG_INT0,
    REG_INT1
  };
  void setMapping(UserName from, CPUName to); // store the mapping
  CPUName getMapping(UserName name) const; // retrieve the mapping
private:
  std::map<UserName, CPUName> m_registerMap;
};

如果您希望存储寄存器的索引/地址,则可以为该类中的寄存器实现 get/set 方法。要么使用模板,要么为不同的数据类型重载模板。

【讨论】:

    【解决方案3】:

    您可以显式使用枚举类型作为函数或构造函数参数,限制调用者使用该枚举。 您不能轻易做的事情是以您建议的方式组合多个枚举定义。

    您可以编写多个构造函数,为欧洲、亚洲等枚举中的每一个编写一个构造函数,但这是可行的,尤其是当您有许多函数需要将这些枚举作为参数时。

    --或--

    您可以定义一个大枚举,并为每个子组定义固定值分隔符,因此您可以将枚举值与这些保护值进行比较以识别子组。如果你这样做,你会失去分组。您可以使用 c++11 常量枚举初始化器在每个大陆的子类中构造枚举值成员 - 但请注意,这些仅适用于 c++17 中的enum class(所以我使用嵌套类技巧来提供成员命名空间强制执行——在 c++17 中你可以有 enum class Location——你可以在 c++11 中写这个但是你不能做 const 初始化程序)。这些值遵循上述分隔符规则,但调用者必须通过子类间接获取名称。

    class Country
    {
      class Location {
        enum Value { 
          None =0,
          Europe = 0x0100,
          Asia =   0x0200,
          //etc
        };
      };
    
      struct Asia {
        const Location::Value Japan { Location::Asia + 1 };
        //etc
      };
      struct Europe {
        const Location::Value UnitedKingdom { Location::Europe + 1 };
        //etc
      };
      // etc
    };
    

    那么你可以拥有

    class myClass {
    public:
      myClass(Country::Location::Value v);
    };
    

    然后调用它

    myClass instance(Country::Asia::Japan);
    

    -- 或者--

    您可以定义另一个结构,其唯一目的是获取各种枚举并将它们转换为大陆和国家索引的一对值。然后,您可以使用该结构作为您的函数参数,并允许从该结构进行自动转换。这意味着您只需进行一次转换,您的代码的调用者不会受到影响。您可以使用保护范围,这样您就不需要显式存储大陆代码,只需原始国家/地区编号在您的所有枚举中都是唯一的。

    【讨论】:

      猜你喜欢
      • 2012-09-23
      • 1970-01-01
      • 2022-01-09
      • 2020-03-03
      • 2015-06-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多