Почему 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()'
Перечислимые типы без границ (т.е. обычные enums
в отличие от enum class
а также enum struct
) обеспечить неявное продвижение до целого числа, т.е. вы можете сделать это:
enum FooType : int { Crazy, Cool };
int val = Crazy; // promotion to integer
Однако, это не работает наоборот:
FooType val = 0; // illegal
Это следует из §7.2 / 5: Каждое перечисление определяет тип, который отличается от всех других типов, в сочетании с §7.2 / 9: Значение перечислителя или объекта типа перечисления с незаданной областью преобразуется в целое число путем интегрального преобразования.
Я полагаю, что причина этого правила довольно очевидна: могут быть (и, как правило, существуют) целочисленные значения, для которых не определен соответствующий перечислитель. В приведенном выше примере преобразование 0
а также 1
было бы теоретически возможно, но преобразование 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
(который неявно повышен до int
):
class Bar : public Foo
{
public:
virtual ~Bar(void) {}
virtual int getType(void)
{
return Hello;
}
};
Обратите внимание, что это работает, только если базовый тип int
(что это потому, что вы исправили это int
в объявлении перечисления), и если перечисление не ограничено (то есть не использует enum class
или же enum struct
).
С ++ не работает так. Идея ковариантных возвращаемых типов работает только для ссылок или указателей на объекты, которые являются подклассами исходного возвращаемого типа.
Когда ты пишешь enum class MyEnum : int
, вы не указываете подкласс, вы указываете, что MyEnum будет реализован типом int.
Вам разрешено только делать следующее:
class Base {
public:
virtual Base* foo() = 0;
};
class Derived : public Base {
public:
Derived* foo();
};
набранный enum
где только недавно приняли в 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 ++!
Почему C ++ не распознает
enum MyEnum : int
как ко-вариант кint
?
Поскольку это не так — тогда как объекты производных типов классов могут неявно рассматриваться как объекты их открытых базовых типов, перечисления со строгим типом, ну, в общем, сильно типизированных. Т.е. они могут не неявно трактоваться как объекты их базового типа, и, как говорится, не являются ковариантными кандидатами.