Виртуальный метод C ++ возвращает различные производные типы

Ссылка на этот вопрос: Тип возвращаемой виртуальной функции 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 () без приведения?

1

Решение

Код не будет компилироваться как написано. Так как 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 здесь вместо этого, чтобы избежать неопределенного поведения, если вы ошибаетесь в динамическом типе.

4

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

Как написано, вы получите ошибки компилятора при вызове .Get ().
Если вы хотите избежать этого, сделайте присваивание базовому классу.

ReturnTypeBase * one = objects[0].Get();
ReturnTypeBase * two = objects[1].Get();

Пока вы обращаетесь к ‘one’ и ‘two’ через абстрактные методы, определенные в базовом классе (например, метод toString ()), у вас не будет проблем с внутренними данными.

Если вы намереваетесь обрабатывать данные одинаково во всех экземплярах базового класса, вы можете вместо этого рассмотреть возможность использования шаблонного класса.

0

По вопросам рекламы [email protected]