用于虚函数返回的枚举变量

时间:2012-11-08 02:07:41

标签: c++ enums c++11 covariance

为什么C ++不会将enum MyEnum : int识别为int的共变体?

示例:http://ideone.com/Ns1O2d

#include <iostream>

enum FooType : int
{
    Crazy = 0,
    Cool
};

enum BarType : int
{
        Hello = Cool + 1,
        World
};

class Foo
{
public:
        Foo(void)
        {
        }

        ~Foo(void)
        {
        }

        virtual int getType(void) 
        {
                        return Crazy;
        }
};

class Bar : public Foo
{
public:
        Bar(void)
        {
        }

        ~Bar(void)
        {
        }

        virtual BarType getType(void)
        {
                return Hello;
        }
};

int main(int argc, char* argv[])
{
        Bar f = Bar();           
        std::cout << f.getType() << std::endl;
        return 0;
}

编译错误:

prog.cpp:43:18: error: conflicting return type specified for 'virtual BarType Bar::getType()'
prog.cpp:26:14: error:   overriding 'virtual int Foo::getType()'

4 个答案:

答案 0 :(得分:3)

非范围的枚举类型(即通常的enums,而不是enum classenum struct)提供隐式提升为整数,即您可以这样做:

enum FooType : int { Crazy, Cool };
int val = Crazy; // promotion to integer

但是,这不起作用:

FooType val = 0;  // illegal

以下是§7.2/ 5:每个枚举定义一个与所有其他类型不同的类型,结合§7.2/ 9:枚举器或对象的值通过整数提升将未范围的枚举类型转换为整数。

我相信这条规则的原因很明显:可以(通常是)整数值,没有定义相应的枚举数。在上面的示例中,理论上可以转换01,但转换2或任何较大的数字都无法转换。

但是,如果枚举的协变与其基础类型(在您的示例中为int),在您定义它的意义上,可能会出现以下情况:

class Foo
{
public:
  virtual ~Foo(void) {}
  virtual int getType(void) 
  {
    return Crazy;
  }
};

class Bar : public Foo
{
public:
  virtual ~Bar(void) {}
  virtual BarType getType(void)
  {
    return Foo::getType();
  }
};

在派生类中,Bar::getType()现已被定义为返回BarType,但它通过调用继承的函数Foo::getType()来完成此操作,这是完全合法的。

如果这是可能的,那么Bar::getType()必须隐式地将int的结果从Foo::getType()转换为int。如上所述,这不可能。


但是,您仍然可以通过以与Bar::getType相同的方式声明Foo:getType来实现代码似乎意图的目标,并返回BarType(隐式提升为{{1} }}):

int

请注意,这只适用于基础类型为class Bar : public Foo { public: virtual ~Bar(void) {} virtual int getType(void) { return Hello; } }; (这是因为您在枚举声明中将其修复为int),并且枚举不是作用域的(即不是使用intenum class)。

答案 1 :(得分:2)

C ++不能那样工作。协变返回类型的概念仅适用于作为原始返回类型的子类的对象的引用或指针。

当您编写enum class MyEnum : int时,您没有指定子类,而是指定MyEnum将由int类型实现。

您只能执行以下操作:

class Base {
  public:
  virtual Base* foo() = 0;
};

class Derived : public Base {
  public:
  Derived* foo();
};

答案 2 :(得分:2)

键入enum s刚刚被C ++采用的地方。 enum在理想世界中应该做很多事情 - 我们应该能够迭代定义的值,我们应该能够将它们变成代数,我们应该像我们一样扩展它们做class es,我们可能应该能够创建一个virtual函数来返回你所要求的协变enum

但我们不能。

现在,我们可以做的是:

class Base {
public:
  virtual int getType() const { return 0; }
};

enum Bird : int { Chicken = 0, Duck = 1 };

class Derived: public Base {
public:
  Bird getBirdType() const { return static_cast<Bird>(getType()); }
  virtual int getType() const override { return Chicken; }
};

旧签名(getType)仍然暴露,新功能(getBirdType)为我们提供了类型更正版本。

如果我们可以写Bird Derived::getType() const override,世界可能会更好,但除非你同意莱布尼兹,否则我们不会生活在那个世界。向C ++添加功能需要花费标准开发时间,并且编译器需要花费时间来实现它。因此,添加到C ++中的功能往往是在市场上的编译器中经过测试的功能,其成本值得获益和需求。

如果您真的想要这个功能,我建议您参与C ++标准化工作!

答案 3 :(得分:2)

  

为什么C ++不会将enum MyEnum : int识别为int的共变体?

因为它不是 - 而派生类类型的对象可能被隐式地视为其公共基类型的对象,所以强类型枚举是强类型。也就是说,他们可能被隐含地视为其基础类型的对象,而且据说这些不是协变候选者。