Why does C++ not recognise enum MyEnum : int as being co-variant to int?
Example: 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;
}
Compilation error:
prog.cpp:43:18: error: conflicting return type specified for 'virtual BarType Bar::getType()'
prog.cpp:26:14: error: overriding 'virtual int Foo::getType()'
Non-scoped enumeration types (i.e. the usual enums, as opposed to enum class and enum struct) provide implicit promotion to integer, i.e you can do this:
enum FooType : int { Crazy, Cool };
int val = Crazy; // promotion to integer
However, this does not work in reverse:
FooType val = 0; // illegal
This follows from §7.2/5: Each enumeration defines a type that is different from all other types, in combination with §7.2/9: The value of an enumerator or an object of an unscoped enumeration type is converted to an integer by integral promotion.
I believe the reason for this rule is quite obvious: There can be (and, generally, are) integer values for which no corresponding enumerator is defined. In the example above, converting 0 and 1 would be theoretically possible, but converting 2 or any larger number could not be converted.
However, if the enumeration were covariant to its underlying type (int in your example), in the sense you defined it, the following would be possible:
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();
}
};
In the derived class, Bar::getType() has now been defined to return a BarType, but it does this by calling the inherited function Foo::getType(), which is entirely legitimate.
If this was possible as written, Bar::getType() would have to implicitly convert the int that results from Foo::getType() to an int. And this can't be, as explained above.
However, you can still achieve what your code seems to intend by declaring Bar::getType in the same way as Foo:getType, and return a BarType (which is implicitly promoted to int):
class Bar : public Foo
{
public:
virtual ~Bar(void) {}
virtual int getType(void)
{
return Hello;
}
};
Note that this only works if the underlying type is int (which it is because you fixed it to int in the declaration of the enumeration), and if the enumeration is not scoped (i.e. not using enum class or enum struct).
C++ does not work like that. The idea of covariant return types only works for references or pointers to objects that are subclasses of the original return type.
When you write enum class MyEnum : int, you are not specifying a subclass, you are specifying that MyEnum will be implemented by the int type.
You are only allowed to do the following:
class Base {
public:
virtual Base* foo() = 0;
};
class Derived : public Base {
public:
Derived* foo();
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With