Переопределить функцию-член с другим типом возврата - PullRequest
21 голосов
/ 23 января 2012

Рассмотрим пример ниже:

#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;
}

Компилятор выдает ошибку для приведенного выше кода, что существует конфликтующий тип для переопределенной функции. Почему невозможно переопределить функцию в производном классе с другим типом возврата?

Я полагаю, чтобы переопределить функцию, виртуальный метод базового класса необходимо переопределить в производном классе. Чтобы переопределить метод, сигнатуры методов должны быть одинаковыми. Поскольку возвращаемый тип не является частью сигнатуры, я верю, что даже если есть разница в возвращаемом типе, метод все равно будет переопределен? В этом случае для приведенного выше кода виртуальная функция func переопределяется в производном классе с другим типом возврата. Но компилятор выдает ошибку. Правильно ли мое понимание?

Ответы [ 5 ]

24 голосов
/ 23 января 2012

Переопределение означает, что метод базового класса или метод производного класса будет вызываться во время выполнения в зависимости от фактического объекта, на который указывает указатель.
Это означает, что:
т.е.Метод базового класса, который может быть вызван, может быть заменен вызовом метода производного класса без каких-либо изменений в вызывающем коде.

Чтобы достичь этого, единственный возможный способ - ограничить типы возврата переопределяющих виртуальных методов так, чтобы они возвращали тот же тип, что и базовый класс, или тип, производный от него (совпадающие типы возврата) иСтандарт обеспечивает соблюдение этого условия.

Если вышеупомянутое условие не выполнялось, было бы окно, чтобы сломать существующий код путем добавления новой функциональности.

11 голосов
/ 23 января 2012

Чтобы переопределить виртуальную функцию, возвращаемое значение должно быть точно таким же *.C ++ будет не автоматически преобразовывать между double и int здесь - в конце концов, как он узнает, какой тип возврата вы хотите при вызове из указателя производного класса?Обратите внимание, что если вы измените часть подписи (параметры, константу и т. Д.), То вы также можете изменить и возвращаемое значение.

* - строго говоря, оно должно быть «ковариантным».Это означает, что возвращаемый тип должен быть подмножеством возвращаемого типа родительской функции.Например, если родительский класс возвращает base *, вы можете вернуть derived *.Так как derived s являются одновременно и base s, компилятор позволяет вам переопределять таким образом.Но вы не можете вернуть совершенно не связанные типы, такие как int и double;только то, что есть неявное преобразование, не означает, что компилятор позволит вам делать такие переопределения.

6 голосов
/ 23 января 2012

См. этот вопрос .Подводя итог, вы можете переопределить виртуальную функцию, используя другой тип возврата, только если типы ковариантны .

2 голосов
/ 23 января 2012

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

См. Следующее:

#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.;

      }
};
0 голосов
/ 23 января 2012

Переопределение невозможно, так как подписи разные. Основной целью переопределения является полиморфизм, но это невозможно в приведенном выше примере

...