Nicht-virtuelle Methoden überschreiben

80

Nehmen wir dieses Szenario in Visual C ++ 2010 an:

#include <iostream>
#include <conio.h>

using namespace std;

class Base
{
public:
    int b;
    void Display()
    {
        cout<<"Base: Non-virtual display."<<endl;
    };
    virtual void vDisplay()
    {
        cout<<"Base: Virtual display."<<endl;
    };
};

class Derived : public Base
{
public:
    int d;
    void Display()
    {
        cout<<"Derived: Non-virtual display."<<endl;
    };
    virtual void vDisplay()
    {
        cout<<"Derived: Virtual display."<<endl;
    };
};

int main()
{
    Base ba;
    Derived de;

    ba.Display();
    ba.vDisplay();
    de.Display();
    de.vDisplay();

    _getch();
    return 0;
};

Theoretisch sollte die Ausgabe dieser kleinen Anwendung sein:

  • Basis: Nicht virtuelle Anzeige.
  • Basis: Virtuelle Anzeige.
  • Basis: Nicht virtuelle Anzeige.
  • Abgeleitet: Virtuelle Anzeige.

Da die Anzeigemethode der Basisklasse keine virtuelle Methode ist, sollte die abgeleitete Klasse sie nicht überschreiben können. Richtig?

Das Problem ist, dass beim Ausführen der Anwendung Folgendes gedruckt wird:

  • Basis: Nicht virtuelle Anzeige.
  • Basis: Virtuelle Anzeige.
  • Abgeleitet: Nicht virtuelle Anzeige.
  • Abgeleitet: Virtuelle Anzeige.

Entweder habe ich das Konzept der virtuellen Methoden nicht verstanden oder in Visual C ++ passiert etwas Seltsames.

Könnte mir jemand mit einer Erklärung helfen?

Leif Lazar
quelle
Sie hätten unbedingt Base: Nicht-virtuelle Anzeige. wenn Sie Ihre Zeile auf ändern de.Base::Display().
v.oddou

Antworten:

122

Ja, Sie verstehen ein wenig falsch.

Die gleichnamige Methode für die abgeleitete Klasse verbirgt in diesem Fall die übergeordnete Methode. Sie können sich vorstellen, dass der Versuch, eine Methode mit demselben Namen wie eine nicht virtuelle Methode der Basisklasse zu erstellen, einen Fehler auslösen würde, wenn dies nicht der Fall wäre. Es ist erlaubt und kein Problem - und wenn Sie die Methode direkt aufrufen, wie Sie es getan haben, wird sie als gut bezeichnet.

Da es sich jedoch nicht um virtuelle C ++ - Methodensuchmechanismen handelt, die Polymorphismus ermöglichen, werden diese nicht verwendet. Wenn Sie beispielsweise eine Instanz Ihrer abgeleiteten Klasse erstellt, aber Ihre 'Display'-Methode über einen Zeiger auf die Basisklasse aufgerufen haben, wird die Methode der Basis aufgerufen, während für' vDisplay 'die abgeleitete Methode aufgerufen wird.

Versuchen Sie beispielsweise, folgende Zeilen hinzuzufügen:

Base *b = &ba;
b->Display();
b->vDisplay();
b = &de;
b->Display();
b->vDisplay();

... und beobachten Sie die Ausgabe wie erwartet:

Basis: Nicht virtuelle Anzeige.
Basis: Virtuelle Anzeige.
Basis: Nicht virtuelle Anzeige.
Abgeleitet: Virtuelle Anzeige.

sje397
quelle
Hi @ sje397, danke für deine Antwort. Können Sie ein Beispiel für den Aufruf der Methode, wie Sie sagten, über einen Zeiger auf die Basisklasse schreiben? Vielen Dank!
Leif Lazar
Wie ich bereits sagte, können Sie AUCH die (nicht virtuelle) Basismethode von der abgeleiteten Instanz aus mithilfe der Syntax für die Bereichsauflösung aufrufen.
v.oddou
Um sicherzugehen, kann ich eine Methode in der Basisklasse definieren und in der abgeleiteten Klasse überschreiben, unabhängig davon, ob sie als virtuell deklariert wird oder nicht. Der einzige Unterschied besteht darin, dass beim Aufrufen dieser Methode, wenn ein Basiszeiger auf ein abgeleitetes Klassenobjekt zeigt, die Methode der Basisklasse, wenn sie nicht virtuell ist, und die Methode der abgeleiteten Klasse, wenn sie virtuell ist, aufgerufen werden. Ist das richtig? Gibt es noch einen anderen Unterschied?
SexyBeast
@Cupidvogel Ja, das ist richtig. Wenn Sie es als "virtuell" deklarieren, verwendet C ++ Mechanismen zur Unterstützung des Polymorphismus und prüft, ob es eine abgeleitete Version der Methode gibt, wenn Sie über einen Basisklassenzeiger aufrufen. Ich kann mir keinen anderen Unterschied vorstellen.
sje397
Reicht es aus, nur die Header-Datei zu ändern? Oder muss die Quelle mit dem Schlüsselwort "virtual" kompiliert werden?
Paul Knopf
13

Ja, Sie haben ein wenig falsch verstanden:

Reine virtuelle Funktionen:

virtual void fun1()=0 -> muss in der abgeleiteten Klasse überschrieben werden

Virtuelle Funktionen:

virtual void fun2() -> kann überschrieben werden

Normale Funktionen:

void fun3() -> überschreibe es nicht

Um einen Laufzeitpolymorphismus zu erreichen, müssen Sie virtuelle Funktionen in c ++ überschreiben

Avinash Aitha
quelle
5

Ich denke, es könnte auch besser sein, es im Kontext der statischen oder dynamischen Bindung zu betrachten.

Wenn die Methode nicht virtuell ist (im Gegensatz zu Java ist sie in C ++ bereits standardmäßig vorhanden), wird die Methode zur Kompilierungszeit an ihren Aufrufer gebunden, sodass das tatsächliche Objekt, auf das zur Laufzeit verwiesen wird, nicht bekannt ist. Der Variablentyp ist also alles, was zählt, was die 'Basis' ist.

stdout
quelle