webentwicklung-frage-antwort-db.com.de

Überschreiben Sie eine Memberfunktion mit einem anderen Rückgabetyp

Betrachten Sie das Beispiel unten:

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

Der Compiler gibt einen Fehler für den obigen Code aus, dass ein in Konflikt stehender Typ für die Überschreibungsfunktion vorliegt. Warum ist es nicht möglich, eine Funktion in der abgeleiteten Klasse mit einem anderen Rückgabetyp zu überschreiben?

Ich glaube, um eine Funktion zu überschreiben, muss die virtuelle Methode der Basisklasse in der abgeleiteten Klasse neu definiert werden. Um eine Methode neu zu definieren, müssen die Signaturen der Methoden gleich sein. Da der Rückgabetyp nicht Teil der Signatur ist, glaube ich, dass selbst wenn sich der Rückgabetyp unterscheidet, die Methode immer noch neu definiert wird. In diesem Fall wird die virtuelle Funktion func in der abgeleiteten Klasse mit einem anderen Rückgabetyp neu definiert. Der Compiler gibt jedoch einen Fehler aus. Ist mein Verständnis richtig?

21
nitin_cherian

Überschreiben bedeutet im Wesentlichen, dass entweder die Base-Klassenmethode oder die abgeleitete Klassenmethode zur Laufzeit aufgerufen wird, abhängig vom tatsächlichen Objekt, auf das der Zeiger zeigt.
Das impliziert:
Das heißt: Jeder Ort, an dem die Basisklassenmethode aufgerufen werden kann, kann durch den Aufruf der abgeleiteten Klassenmethode ersetzt werden, ohne dass der Aufrufcode geändert wird. 

Um dies zu erreichen, besteht die einzige Möglichkeit darin, die Rückgabetypen der überschreibenden virtuellen Methoden so einzuschränken, dass sie denselben Typ wie die Basisklasse oder einen davon abgeleiteten Typ zurückgeben (kovariante Rückgabetypen) und der Standard diese Bedingung durchsetzen. 

Wenn die obige Bedingung nicht erfüllt ist, wird ein Fenster geöffnet, in dem der vorhandene Code durch Hinzufügen neuer Funktionen beschädigt wird.

23
Alok Save

Um eine virtuelle Funktion zu überschreiben, muss der Rückgabewert exakt derselbe * sein. C++ konvertiert nicht automatisch zwischen double und int hier - woher soll es denn wissen, welchen Rückgabetyp Sie aus einem abgeleiteten Klassenzeiger aufrufen möchten? Wenn Sie einen Teil der Signatur ändern (Parameter, Konstante usw.), können Sie auch den Rückgabewert ändern.

* - streng genommen muss es "kovariant" sein. Dies bedeutet, dass der von Ihnen zurückgegebene Typ eine Teilmenge des Rückgabetyps der übergeordneten Funktion sein muss. Wenn die übergeordnete Klasse beispielsweise einen base * zurückgibt, können Sie einen derived * zurückgeben. Da deriveds gleichzeitig auch bases sind, können Sie den Compiler auf diese Weise überschreiben. Sie können jedoch keine völlig unabhängigen Typen wie int und double zurückgeben. Nur weil es eine implizite Konvertierung gibt, bedeutet das nicht, dass der Compiler diese Art von Überschreibung ausführen kann.

10
bdonlan

Siehe diese Frage . Zusammenfassend können Sie eine virtuelle Funktion nur mit einem anderen Rückgabetyp überschreiben, wenn die Typen covariant sind.

6
ezod

Wenn Sie überschreiben möchten, sollten Sie versuchen, die Vorlage zu verwenden. 

Siehe folgendes:

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

Natürlich müssen Sie es nicht für zwei verschiedene Klassen auf diese Weise deklarieren.

class base
{
   public:
      int func()
      {
         cout << "vfunc in base class\n";
         return 0;
      }  

      double func(){
        cout << "vfunc for double class\n";
        return 2.;

      }
};
2
Werner

Das Überschreiben ist nicht möglich, da die Signaturen unterschiedlich sind. Der Hauptzweck des Überschreibens ist der Polymorphismus, aber im obigen Beispiel ist dies nicht möglich

0
kvk