Переопределить функцию-член с другим типом возврата
Рассмотрим пример ниже:
#include <iostream>
using namespace std;
class base
{
public:
virtual int func()
{
cout << "vfunc in base class\n";
return 0;
}
};
class derived: public base
{
public:
double func()
{
cout << "vfunc in derived class\n";
return 0;
}
};
int main()
{
base *bptr = new derived;
bptr->func();
return 0;
}
Компилятор дает ошибку для вышеуказанного кода, что для функции overriden существует конфликтный тип. Почему невозможно переопределить функцию в производном классе с другим возвращаемым типом?
Я считаю, что для переопределения функции виртуальный метод базового класса должен быть переопределен в производном классе. Чтобы переопределить метод, подписи методов должны быть одинаковыми. Поскольку тип возврата не является частью подписи, я считаю, что даже если есть разница в типе возврата, метод все равно будет переопределен? В этом случае для кода выше виртуальная функция func
переопределяется в производном классе с другим типом возвращаемого значения. Но компилятор выдает ошибку. Правильно ли я понимаю?
Ответы
Ответ 1
Переопределение по существу означает, что либо метод базового класса, либо метод класса Derived будут вызываться во время выполнения в зависимости от фактического объекта, на который указывает указатель.
Это означает, что:
i.e: Каждое место, где может быть вызван метод базового класса, может быть заменено вызовом метода Derived класса без изменения кода вызова.
Чтобы достичь этого, единственный возможный способ - ограничить возвращаемые типы переопределяющих виртуальных методов возвратом того же типа, что и базовый класс, или тип, полученный из этого (типы возвращаемых вариантов совместного использования), а стандарт применяет этот состояние.
Если вышеуказанное условие не было на месте, оно оставит окно, чтобы сломать существующий код, добавив новые функции.
Ответ 2
Чтобы переопределить виртуальную функцию, возвращаемое значение должно быть точно таким же *. С++ не будет автоматически конвертировать между double
и int
здесь - в конце концов, как он узнает, какой тип возврата вы хотите получить при вызове из указателя производного класса? Обратите внимание: если вы измените часть подписи (параметры, константа и т.д.), Вы также можете изменить возвращаемое значение.
* - строго говоря, он должен быть "ковариантным". Это означает, что возвращаемый вами тип должен быть подмножеством возвращаемого типа родительской функции. Например, если родительский класс возвращает a base *
, вы можете вернуть derived *
. Поскольку derived
одновременно также base
s, компилятор позволяет вам переопределить таким образом. Но вы не можете возвращать совершенно несвязанные типы, такие как int
и double
; просто потому, что неявное преобразование не означает, что компилятор позволит вам сделать это переопределение.
Ответ 3
См. этот вопрос. Подводя итог, вы можете только переопределить виртуальную функцию с помощью другого типа возврата, если типы covariant.
Ответ 4
Если вы хотите переопределить, попробуйте использовать шаблон.
См. следующее:
#include <iostream>
using namespace std;
class base
{
public:
template<typename X> X func()
{
cout << "vfunc in base class\n";
return static_cast<X>(0);
}
};
class derived: public base
{
public:
template<typename X> X func()
{
cout << "vfunc in derived class\n";
return static_cast<X>(2);
}
};
int main()
{
derived *bptr = new derived;
cout << bptr->func<int>() << endl;
cout << dynamic_cast<base*>(bptr)->func<int>() << endl;
derived *bptr2 = new derived;
cout << bptr->func<double>() << endl;
cout << dynamic_cast<base*>(bptr)->func<int>() << endl;
return 0;
}
Конечно, вам не нужно объявлять это на двух разных классах таким образом:
class base
{
public:
int func()
{
cout << "vfunc in base class\n";
return 0;
}
double func(){
cout << "vfunc for double class\n";
return 2.;
}
};
Ответ 5
Переопределение невозможно, так как подписи разные. Основной целью переопределения является полиморфизм, но это невозможно в приведенном выше примере