Mit der unten angegebenen Strukturdefinition ...
struct A {
virtual void hello() = 0;
};
Ansatz 1:
struct B : public A {
virtual void hello() { ... }
};
Ansatz 2:
struct B : public A {
void hello() { ... }
};
Gibt es einen Unterschied zwischen diesen beiden Möglichkeiten, die Hallo-Funktion zu überschreiben?
c++
overriding
virtual-functions
Anarki
quelle
quelle
Antworten:
Sie sind genau das gleiche. Es gibt keinen Unterschied zwischen ihnen, außer dass der erste Ansatz mehr Eingabe erfordert und möglicherweise klarer ist.
quelle
override
Schlüsselwort zu verwenden.Die 'Virtualität' einer Funktion wird implizit weitergegeben. Mindestens ein von mir verwendeter Compiler generiert jedoch eine Warnung, wenn das
virtual
Schlüsselwort nicht explizit verwendet wird. Sie können es daher verwenden, um den Compiler ruhig zu halten.Aus rein stilistischer Sicht macht das Einbeziehen des
virtual
Schlüsselworts dem Benutzer deutlich, dass die Funktion virtuell ist. Dies ist für jeden wichtig, der B weiter unterordnet, ohne die Definition von A überprüfen zu müssen. Für tiefe Klassenhierarchien wird dies besonders wichtig.quelle
Das
virtual
Schlüsselwort ist in der abgeleiteten Klasse nicht erforderlich. Hier ist die unterstützende Dokumentation aus dem C ++ Draft Standard (N3337) (Schwerpunkt Mine):quelle
Nein, das
virtual
Schlüsselwort für die virtuellen Funktionsüberschreibungen abgeleiteter Klassen ist nicht erforderlich. Erwähnenswert ist jedoch eine damit verbundene Gefahr: ein Fehler beim Überschreiben einer virtuellen Funktion.Der Fehler beim Überschreiben tritt auf, wenn Sie beabsichtigen, eine virtuelle Funktion in einer abgeleiteten Klasse zu überschreiben, aber einen Fehler in der Signatur machen, sodass eine neue und andere virtuelle Funktion deklariert wird. Diese Funktion kann eine Überladung der Basisklassenfunktion sein oder sich im Namen unterscheiden.
virtual
Unabhängig davon, ob Sie das Schlüsselwort in der abgeleiteten Klassenfunktionsdeklaration verwenden oder nicht, kann der Compiler nicht erkennen, dass Sie beabsichtigen, eine Funktion aus einer Basisklasse zu überschreiben.Diese Gefahr wird jedoch dankenswerterweise durch die explizite C ++ 11-Funktion zum Überschreiben von Sprachen behoben, mit der der Quellcode klar angeben kann, dass eine Mitgliedsfunktion eine Basisklassenfunktion überschreiben soll:
Der Compiler gibt einen Fehler zur Kompilierungszeit aus und der Programmierfehler ist sofort offensichtlich (möglicherweise sollte die Funktion in Derived a
float
als Argument verwendet haben).Siehe WP: C ++ 11 .
quelle
Das Hinzufügen des Schlüsselworts "virtuell" ist eine gute Vorgehensweise, da es die Lesbarkeit verbessert, jedoch nicht erforderlich ist. Funktionen, die in der Basisklasse als virtuell deklariert wurden und in den abgeleiteten Klassen dieselbe Signatur haben, werden standardmäßig als "virtuell" betrachtet.
quelle
Es gibt keinen Unterschied für den Compiler, wenn Sie das
virtual
in die abgeleitete Klasse schreiben oder weglassen.Sie müssen sich jedoch die Basisklasse ansehen, um diese Informationen zu erhalten. Daher würde ich empfehlen, das
virtual
Schlüsselwort auch in die abgeleitete Klasse einzufügen , wenn Sie dem Menschen zeigen möchten, dass diese Funktion virtuell ist.quelle
Es gibt einen erheblichen Unterschied, wenn Sie Vorlagen haben und Basisklassen als Vorlagenparameter verwenden:
Der lustige Teil davon ist, dass Sie jetzt Schnittstellen- und Nicht-Schnittstellenfunktionen definieren können, um später Klassen zu definieren. Dies ist nützlich für das Interworking von Schnittstellen zwischen Bibliotheken (verlassen Sie sich nicht darauf als Standardentwurfsprozess einer einzelnen Bibliothek). Es kostet Sie nichts, dies für alle Ihre Klassen zuzulassen - Sie könnten sogar
typedef
B zu etwas, wenn Sie möchten.Beachten Sie, dass Sie in diesem Fall möglicherweise auch Kopier- / Verschiebungskonstruktoren als Vorlagen deklarieren möchten: Wenn Sie über verschiedene Schnittstellen konstruieren können, können Sie zwischen verschiedenen
B<>
Typen wechseln .Es ist fraglich, ob Sie Unterstützung für
const A&
in hinzufügen solltent_hello()
. Der übliche Grund für dieses Umschreiben besteht darin, von einer vererbungsbasierten Spezialisierung zu einer vorlagenbasierten zu wechseln, hauptsächlich aus Leistungsgründen. Wenn Sie die alte Benutzeroberfläche weiterhin unterstützen, können Sie die alte Nutzung kaum erkennen (oder davon abhalten).quelle
Das
virtual
Schlüsselwort sollte zu Funktionen einer Basisklasse hinzugefügt werden, um sie überschreibbar zu machen. In Ihrem Beispielstruct A
ist die Basisklasse.virtual
bedeutet nichts für die Verwendung dieser Funktionen in einer abgeleiteten Klasse. Wenn Sie jedoch möchten, dass Ihre abgeleitete Klasse auch selbst eine Basisklasse ist und diese Funktion überschreibbar ist, müssen Sie dievirtual
dort ablegen .Hier
C
erbt vonB
,B
ist also nicht die Basisklasse (es ist auch eine abgeleitete Klasse), undC
ist die abgeleitete Klasse. Das Vererbungsdiagramm sieht folgendermaßen aus:Daher sollten Sie die
virtual
Funktionen vor potenzielle Basisklassen stellen, die möglicherweise Kinder haben.virtual
ermöglicht Ihren Kindern, Ihre Funktionen zu überschreiben. Es ist nichts Falsches daran, dievirtual
Funktionen innerhalb der abgeleiteten Klassen vor zu stellen, aber es ist nicht erforderlich. Es wird jedoch empfohlen, da jemand, der von Ihrer abgeleiteten Klasse erben möchte, nicht erfreut wäre, dass das Überschreiben der Methode nicht wie erwartet funktioniert.Stellen Sie also
virtual
Funktionen in allen an der Vererbung beteiligten Klassen vor, es sei denn, Sie wissen sicher, dass die Klasse keine untergeordneten Elemente hat, die die Funktionen der Basisklasse überschreiben müssten. Es ist eine gute Praxis.quelle
Ich werde auf jeden Fall das virtuelle Schlüsselwort für die untergeordnete Klasse einschließen, weil
quelle