3

为什么 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

4 回答 4

3

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

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

但是,这不起作用:

FooType val = 0;  // illegal

这来自第 7.2/5 节:每个枚举定义了一个不同于所有其他类型的类型,结合第 7.2/9 节:枚举数的值或无作用域枚举类型的对象通过整数提升转换为整数.

我相信这条规则的原因很明显:可能(并且通常是)整数值没有定义相应的枚举数。在上面的例子中,理论上可以转换0和,但转换或任何更大的数字都不能转换。12

但是,如果枚举与其基础类型(在您的示例中)是协变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()现在已经定义返回 a BarType,但它通过调用继承的函数来实现Foo::getType(),这是完全合法的。

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


Bar::getType但是,您仍然可以通过以与 相同的方式声明Foo:getType并返回 a BarType(隐式提升为)来实现您的代码似乎想要的内容int

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

请注意,这仅在基础类型是int(这是因为您int在枚举的声明中将其固定)并且枚举没有作用域(即不使用enum classor enum struct)时才有效。

于 2012-11-08T02:49:42.093 回答
2

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

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

您只能执行以下操作:

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

class Derived : public Base {
  public:
  Derived* foo();
};
于 2012-11-08T03:09:11.797 回答
2

typed enums 最近才被 C++ 采用。在一个理想的世界里,s 应该做很多事情enum——我们应该能够迭代定义的值,我们应该能够将它们变成代数,我们应该被允许像我们一样扩展它们class,并且我们可能应该能够像您要求的那样创建一个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; }
};

旧签名getTypegetBirdType

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

如果您真的想要该功能,我鼓励您参与 C++ 标准化工作!

于 2012-11-08T03:18:43.657 回答
2

为什么 C++ 不能识别enum MyEnum : int为与 的协变int

因为它不是——虽然派生类类型的对象可能被隐式视为其公共基类型的对象,但强类型枚举是强类型的。即,它们可能不会被隐含地视为其基础类型的对象,也就是说,它们不是协变候选对象。

于 2012-11-08T04:28:37.690 回答