Тип возврата виртуальной функции

У меня в базовом классе чисто виртуальная функция, определенная как
виртуальный int GetData() const = 0;

В каждом из производных классов я определяю enum и пытаюсь переопределить функцию GetData.
(производное от класса специфическое перечисление) значение;

Например:

class Derived1 : public Base
{
public :
enum D1
{
d1_1 = 0,
d1_2 = 60,
...
d1_100
};
D1 GetData () const;
};
class Derived2 : public Base
{
public :
enum D2
{
d2_1 = 10,
d2_2 = 39,
...
d2_300
};
D2 GetData () const;
};

Очень важно сказать, что я не могу определить один и тот же диапазон для всех перечисляемых значений из всех классов.
Приведенный выше код генерирует ошибки компиляции:

error C2555: : overriding virtual function return type differs and is not covariant

Любые советы — как это решить?

1

Решение

В вашем конкретном случае это тот факт, что ваш virtual Метод Возвращает примитивный тип, который не имеет ковариации, поскольку его нельзя поместить в общий тип, такой как System.Object в C #.
Вам необходимо определить класс, который будет служить базовым классом для всех возвращаемых типов, чтобы заполнить ковариацию.

Из Википедии:

Within the type system of a programming language, covariance and contravariance refers to the
ordering of types from narrower to wider and their interchangeability or equivalence in certain
situations (such as parameters, generics, and return types).

covariant: converting from a specialized type (Cats) to a more general type (Animals):
Every cat is an animal.

Вот это ссылка на статью.

2

Другие решения

Изменение типа возврата виртуальных функций допускается только в том случае, если вы заменяете указатель / ссылку на базовый класс указателем / ссылкой на производный класс, поскольку одну можно безопасно привести к другой. В то время как типы enum и int совместимы, они технически не связаны. Просто использовать int везде, поскольку имя enum просто украшение и ни на что не влияет.

1

Ваш дизайн должен быть исправлен, но в отношении только технический ты можешь сделать

class Derived1
: public Base
{
public:
enum D1
{
d1_1 = 0,
d1_2 = 60,
...
d1_100
};
D1 GetD1Data () const;
int GetData() const override { return GetD1Data(); }
};
1

Согласно C ++ 11 ISO 10.3 / 7:

тип возврата переопределяющей функции должен быть идентичен типу возврата переопределенной функции или ковариант с классами функций. Если функция D :: f переопределяет функцию B :: f, возвращаемые типы функции являются ковариантными, если они удовлетворяют следующим критериям:

оба являются указателями на классы, оба являются lvalue ссылками на классы, или оба являются rvalue ссылками на классы

— класс в возвращаемом типе B :: f является тем же классом, что и класс в возвращаемом типе D :: f, или является однозначным и доступным прямым или косвенным базовым классом класса в возвращаемом типе D: : е

— и указатели, и ссылки имеют одинаковую квалификацию cv, а тип класса в возвращаемом типе D :: f имеет ту же квалификацию cv, что и квалификационный класс или меньше, чем тип класса в возвращаемом типе B :: f.

Ковариация разрешена только для указателей, ссылок на lvalue / rvalue. Я предполагаю, что вы не хотите возвращать enum по ссылке или по указателю.

Но, если вы принимаете статический поток локального буфера, вы можете использовать следующий подход:

LIVE DEMO

class EnumA
{
int value_;
public:
explicit EnumA(int v)
: value_{v}
{}
int value() const
{
return value_;
}
};
struct EnumB: EnumA
{
enum EnumB_T{one,two};
explicit EnumB(EnumB_T v)
: EnumA{v}
{}
EnumB_T value() const
{
return EnumB_T(EnumA::value());
}
};

struct A
{
virtual const EnumA &func() const
{
static thread_local EnumA result{0};
return result = EnumA{1};
}
};

struct B: A
{
virtual const EnumB &func() const override
{
static thread_local EnumB result{EnumB::one};
return result = EnumB{EnumB::two};
}
};
1