Was ist die Verwendung, wenn ich eine Implementierung für eine reine virtuelle Funktion in C ++ zur Verfügung stelle

8

Ich weiß, dass es für eine reine virtuelle Funktion in Ordnung ist, eine Implementierung zu haben. Warum ist es so? Gibt es Konflikte für die beiden Konzepte? Was ist die Verwendung? Kann jemand irgendein Beispiel anbieten?

    
skydoor 25.03.2010, 19:42
quelle

6 Antworten

6

Wurde in GotW # 31 angesprochen. Zusammenfassung:

  

Dafür gibt es drei Hauptgründe   mach das. # 1 ist alltäglich, # 2 ist   ziemlich selten, und # 3 ist ein Workaround   gelegentlich von fortgeschrittenen verwendet   Programmierer arbeiten mit schwächeren   Compiler.

     

Die meisten Programmierer sollten nur # 1 benutzen.

... Was für reine virtuelle Destruktoren ist.

    
Alexander Torstling 25.03.2010, 19:48
quelle
7

In Effektives C ++ gibt Scott Meyers das Beispiel, dass es nützlich ist, wenn Sie Code durch Vererbung wiederverwenden. Er beginnt damit:

%Vor%

Jetzt werden ModelA und ModelB auf die gleiche Weise geflogen, und das wird als eine übliche Methode angesehen, ein Flugzeug zu fliegen, also ist der Code in der Basisklasse. Allerdings werden nicht alle -Ebenen geflogen, und wir denken, dass Ebenen polymorph sind, also ist es virtuell.

Jetzt fügen wir ModelC hinzu, das anders geflogen sein muss, aber wir machen einen Fehler:

%Vor%

Hoppla! ModelC wird abstürzen. Meyers würde es vorziehen, wenn der Compiler uns vor unserem Fehler warnt.

Also macht er fly rein virtuell in Airplane mit einer Implementierung und setzt dann in ModelA und ModelB:

%Vor%

Nun, wenn wir nicht ausdrücklich in unserer abgeleiteten Klasse angeben, dass wir das Standardflugverhalten wollen, bekommen wir es nicht. Also, anstatt nur die Dokumentation, die uns alle Dinge sagt, die wir über unser neues Flugzeugmodell überprüfen müssen, sagt uns auch der Compiler.

Das macht den Job, aber ich denke, es ist ein bisschen schwach. Idealerweise haben wir stattdessen einen BoringlyFlyable-Mix, der die Standardimplementierung von fly enthält, und Code auf diese Weise wiederverwenden, anstatt Code in eine Basisklasse zu setzen, die bestimmte Dinge über Flugzeuge voraussetzt, die keine Anforderungen an Flugzeuge sind. Aber das erfordert CRTP, wenn die Funktion fly tatsächlich etwas Bedeutendes tut:

%Vor%

Wenn PlaneA die Vererbung von BoringlyFlyable deklariert, aktiviert es über die Schnittstelle, dass es gültig ist, es auf die Standard-Art zu fliegen. Beachten Sie, dass BoringlyFlyable reine virtuelle Funktionen definieren könnte: vielleicht wäre getWings eine gute Abstraktion. Aber da es eine Vorlage ist, muss es nicht.

Ich habe das Gefühl, dass dieses Muster alle Fälle ersetzen kann, in denen Sie eine reine virtuelle Funktion mit einer Implementierung versehen hätten - die Implementierung kann stattdessen in ein Mixing gehen, welche Klassen erben können, wenn sie es wollen. Aber ich kann nicht sofort beweisen, dass (zum Beispiel, wenn Airplane::fly private Mitglieder verwendet, dann erfordert es eine erhebliche Neugestaltung, um es auf diese Weise zu tun), und CRTP ist wohl für den Anfänger sowieso ein wenig leistungsfähig. Außerdem ist es etwas mehr Code, der nicht wirklich Funktionalität oder Typsicherheit hinzufügt, es macht nur deutlich, was bereits in Meyers Entwurf implizit ist, dass einige Dinge nur durch Flattern ihrer Flügel fliegen können, während andere stattdessen andere Dinge tun müssen. Also ist meine Version keinesfalls ein totales Shoo-In.

    
Steve Jessop 25.03.2010 21:05
quelle
2

Es gibt keinen Konflikt mit den beiden Konzepten, obwohl sie selten zusammen benutzt werden (wie OO-Puristen es nicht versöhnen können, aber das geht über den Rahmen dieser Frage / Antwort hinaus).

Die Idee ist, dass der rein virtuellen Funktion eine Implementierung gegeben wird, während gleichzeitig Unterklassen gezwungen werden, diese Implementierung zu überschreiben. Die Unterklassen können die Basisklassenfunktion aufrufen, um ein Standardverhalten bereitzustellen. Die Basis kann nicht instanziiert werden (sie ist "abstrakt"), weil die virtuelle (n) Funktion (en) rein ist, obwohl sie möglicherweise eine Implementierung hat.

    
user123456 25.03.2010 19:47
quelle
1

Wikipedia fasst das gut zusammen:

  

Obwohl rein virtuelle Methoden   in der Regel keine Implementierung in   die Klasse, die sie für rein erklärt   Virtuelle Methoden in C ++ sind erlaubt   eine Implementierung in ihrem enthalten   Klasse deklarieren, Fallback oder bereitstellen   Standardverhalten einer abgeleiteten Klasse   kann bei Bedarf delegieren.

Normalerweise müssen Sie keine Basisklassenimplementierungen für reine virtuelle Systeme bereitstellen. Aber es gibt eine Ausnahme: reine virtuelle Destruktoren . Wenn Ihre Basisklasse einen reinen virtuellen Destruktor hat, muss sie eine Implementierung haben . Warum brauchen Sie einen reinen virtuellen Destruktor anstatt nur einen virtuellen? In der Regel, um eine Basisklasse abstrakt zu machen, ohne dass eine andere Methode implementiert werden muss. Beispielsweise können Sie in einer Klasse, in der Sie die Standardimplementierung sinnvollerweise für jede Methode verwenden können, aber nicht möchten, dass Benutzer die Basisklasse instanziieren, nur den Destruktor als rein virtuell markieren.

BEARBEITEN:

Hier ist ein Code, der einige Möglichkeiten zum Aufrufen der Basisimplementierung veranschaulicht:

%Vor%     
John Dibling 25.03.2010 19:46
quelle
0

Auf diese Weise können Sie eine funktionierende Implementierung bereitstellen, müssen aber dennoch vom Implementierer der untergeordneten Klasse explizit aufgerufen werden.

    
Klaim 25.03.2010 19:46
quelle
0

Nun, wir haben schon einige gute Antworten .. Ich bin langsam beim Schreiben ..

Mein Gedanke wäre zum Beispiel eine Init-Funktion, die try {} catch {} hat, was bedeutet, dass sie nicht in einen Konstruktor eingefügt werden sollte:

%Vor%     
Default 25.03.2010 19:47
quelle

Tags und Links