Erstellt C ++ den Standardkonstruktor / Destruktor / Konstruktor kopieren / Zuweisungsoperator kopieren für die reine virtuelle Klasse?

8

Generieren C ++ - Compiler die Standardfunktionen wie Konstruktor / Destruktor / Kopierkonstruktor für diese "Klasse"?

%Vor%

Ich meine, es ist nicht möglich, diese "Klasse" zu instanziieren, daher denke ich, dass keine Standardfunktionen generiert werden. Andernfalls sagen die Leute, dass Sie einen virtuellen Destruktor verwenden müssen. Das heißt, wenn ich den Destruktor nicht virtuell definiere, wird er standardmäßig erstellt, nicht virtuell.

Außerdem möchte ich wissen, ob es sinnvoll ist, einen virtuellen Destruktor für ein reines virtuelles Interface zu definieren, wie oben? (Also werden hier keine Zeiger oder Daten verwendet, also muss nichts zerstört werden)

Danke.

    
user1911091 23.01.2014, 11:33
quelle

4 Antworten

1
  

Außerdem möchte ich wissen, ob es sinnvoll ist, einen virtuellen Destruktor für ein reines virtuelles Interface zu definieren, wie oben? (Also werden hier keine Zeiger oder Daten verwendet, also muss nichts zerstört werden)

Es ist nicht nur vernünftig, es wird empfohlen. Dies liegt daran, dass im Falle virtueller Funktions-Hierarchien (automatisch) der Aufruf eines Destruktors einer spezialisierten Klasse auch alle Destruktoren seiner Basisklassen aufruft. Wenn sie nicht definiert sind, sollten Sie einen Verknüpfungsfehler erhalten.

Wenn Sie in Ihrer Klasse mindestens eine virtuelle Funktion definieren, sollten Sie auch einen virtuellen Destruktor definieren.

Der Destruktor kann mit =default though:

definiert werden

Hier ist ein korrigiertes (kompilierbares) Codebeispiel:

%Vor%     
utnapistim 23.01.2014, 11:40
quelle
3

Ja.

Es gibt keine Formulierung, die erfordert, dass die Klasse instanziierbar ist, damit diese speziellen Memberfunktionen implizit deklariert werden.

Dies ist sinnvoll - nur weil Sie die Basis nicht instanziieren können, bedeutet dies nicht, dass eine abgeleitete Klasse diese Funktionen nicht verwenden möchte.

%Vor%

Siehe:

  • §12.1 / 5 (ctor)
  • §12.8 / 9 (move)
  • §12.8 / 20 (Kopie)
quelle
1
  

Außerdem möchte ich wissen, ob es sinnvoll ist, einen virtuellen Destruktor für ein reines virtuelles Interface zu definieren, wie oben? (Also werden hier keine Zeiger oder Daten verwendet, also muss nichts zerstört werden)

Werden die abgeleiteten Klassen jemals etwas in ihren Destruktoren tun? Kannst du dir sicher sein, dass sie das niemals tun werden, selbst wenn jemand anderes die Entwicklung übernimmt?

Der ganze Sinn eines virtuellen Destruktors besteht nicht darin, sicherzustellen, dass die Basisklasse richtig zerstört wird, das wird sowieso passieren. Der Punkt ist, dass der Destruktor der abgeleiteten Klasse aufgerufen wird, wenn Sie eine generische Schnittstelle verwenden:

%Vor%

Wenn a den Gültigkeitsbereich verlässt, warum ist ifstream geschlossen? Da der Destruktor das Objekt mithilfe des virtuellen Destruktors löscht.

    
Christopher Creutzig 23.01.2014 14:12
quelle
0

Dies betrifft die zweite Frage zum Deklarieren eines virtuellen Destruktors für eine abstrakte Basisklasse (z. B. ist mindestens eine Mitgliedsfunktion rein virtuell). Hier ist ein Beispiel aus der realen Welt des LLVM clang ++ Compilers, der ein potentielles Problem entdeckt. Dies geschah mit der Befehlszeilen-Tools-Version, die von Apple Developer für das Mac OS X Mavericks-Betriebssystem bereitgestellt wurde.

Angenommen, Sie verfügen über eine Sammlung abgeleiteter Klassen, die letztendlich über das Elternelement mit der abstrakten Basisklasse verfügen, um die gemeinsame Schnittstelle zu definieren. Dann ist es notwendig, einen Speicherbehälter wie einen Vektor zu haben, der absichtlich deklariert wird, um einen Zeiger auf die abstrakte Basisklasse für jedes Element zu speichern. Später, nach guten technischen Praktiken, müssen die Container-Elemente "gelöscht" werden und der Speicher zum Heap zurückgegeben werden. Der einfachste Weg, dies zu tun, besteht darin, den Vektor Element für Element zu durchlaufen und die Löschoperation für jedes Element aufzurufen.

Nun, wenn die abstrakte Basisklasse den Destruktor nicht als virtuell deklariert, gibt der clang ++ - Compiler eine freundliche Warnung darüber aus, den nicht virtuellen Destruktor für eine abstrakte Klasse aufzurufen. Beachten Sie, dass in der Realität nur die abgeleiteten Klassen aus dem Heap mit Operator new zugewiesen werden. Der abgeleitete Klassen-Zeigertyp aus der Vererbungsbeziehung ist tatsächlich der abstrakte Basis-Klassentyp (z. B. die Is-a-Beziehung).

Wenn der abstrakte Basisklassendestruktor nicht virtuell ist, wie wird dann der korrekte Destruktor der abgeleiteten Klasse aufgerufen, um den Speicher freizugeben? Im besten Fall weiß der Compiler besser (macht zumindest potentiell mit C ++ 11) und macht es möglich. Wenn die Option -Wall Compiler aktiviert ist, sollte mindestens die Kompilierungswarnung angezeigt werden. Im schlimmsten Fall wird der abgeleitete Klassendestruktor jedoch niemals erreicht, und der Speicher wird niemals zum Heap zurückgegeben. Daher gibt es jetzt ein Speicherleck, das sehr schwierig aufzuspüren und zu beheben ist. Alles was es braucht, ist eine einzige Hinzufügung von "virtual" zur abstrakten Basisklassen-Destruktor-Deklaration.

Beispielcode:

%Vor%

Um diesen potenziellen Speicherverlust zu beheben, muss die abstrakte Basisklasse ihren Destruktor als virtuell deklarieren. Nichts anderes ist erforderlich. Die abstrakte Basisklasse wird nun zu:

%Vor%

Beachten Sie, dass die abstrakte Basisklasse zur Zeit leere Konstruktor- und Destruktor-Körper hat. Wie oben erwähnt, erstellt der Compiler einen Standardkonstruktor, einen Destruktor und einen Kopierkonstruktor für eine abstrakte Basisklasse (falls nicht vom Entwickler definiert). Es wird dringend empfohlen, eine der C ++ - Programmiersprache-Editionen durch den C ++ - Ersteller Bjarne Stroustrup für weitere Details zu abstrakten Basisklassen zu überprüfen.

    
CPlusPlus OOA and D 19.02.2014 11:08
quelle

Tags und Links