Ссылка на этот вопрос: Тип возвращаемой виртуальной функции C ++
Давайте рассмотрим следующий набор объектов.
class ReturnTypeBase
{
};
class ReturnTypeDerived1 : public ReturnTypeBase
{
public:
int x;
};
class ReturnTypeDerived2 : public ReturnTypeBase
{
public:
float y;
};
class Base
{
public:
virtual ReturnTypeBase* Get() = 0;
};
class Derived1: public Base
{
public:
virtual ReturnTypeDerived1* Get()
{
return new ReturnTypeDerived1();
}
};
class Derived2: public Base
{
public:
virtual ReturnTypeDerived2* Get()
{
return new ReturnTypeDerived2();
}
};
Можно ли использовать эти объекты следующим образом?
Base* objects[2];
objects[0] = new Derived1();
objects[1] = new Derived2();
ReturnTypeDerived1* one = objects[0]->Get();
ReturnTypeDerived2* two = objects[1]->Get();
Я предполагаю, поскольку возвращаемые типы являются ковариантными (?), Что набор объектов выше является допустимым C ++. Будет ли вызван соответствующий метод Get ()? Можно ли указателям один / два присвоить возвращаемое значение метода Get () без приведения?
Код не будет компилироваться как написано. Так как objects[0]
имеет статический тип Base*
вспомнив Get
функция приводит к указателю со статическим типом ReturnTypeBase*
возвращается Поскольку это переопределенная виртуальная функция, производный класс Get
функция будет вызываться так, как вы ожидаете, и возвращаемый указатель будет фактически указывать на ReturnTypeDerived1
объект, но компилятор не может доказать это. Вам понадобится приведение:
auto one = static_cast<ReturnTypeDerived1*>(objects[0]->Get());
auto two = static_cast<ReturnTypeDerived2*>(objects[1]->Get());
Если вы делаете ReturnTypeBase
полиморфный тип, вы можете использовать dynamic_cast
здесь вместо этого, чтобы избежать неопределенного поведения, если вы ошибаетесь в динамическом типе.
Как написано, вы получите ошибки компилятора при вызове .Get ().
Если вы хотите избежать этого, сделайте присваивание базовому классу.
ReturnTypeBase * one = objects[0].Get();
ReturnTypeBase * two = objects[1].Get();
Пока вы обращаетесь к ‘one’ и ‘two’ через абстрактные методы, определенные в базовом классе (например, метод toString ()), у вас не будет проблем с внутренними данными.
Если вы намереваетесь обрабатывать данные одинаково во всех экземплярах базового класса, вы можете вместо этого рассмотреть возможность использования шаблонного класса.