standardmäßig überschreiben von virtuellen Destruktor
Jeder weiß, dass die desructor der Basis-Klasse in der Regel werden virtuelle. Aber was ist über den Destruktor der abgeleiteten Klasse? In C++11 wir haben das Schlüsselwort "override" und die Fähigkeit zur Nutzung der Standard-Destruktor explizit.
struct Parent
{
std::string a;
virtual ~Parent()
{
}
};
struct Child: public Parent
{
std::string b;
~Child() override = default;
};
Ist es nicht richtig zu verwenden Sie die beiden Schlüsselwörter "override" und "=default" im Destruktor der abgeleiteten Klasse? Werden compiler generieren, die richtigen virtuellen Destruktor in diesem Fall?
Wenn ja, dann können wir denken, dass es ist guter Programmierstil, und wir sollten uns immer deklarieren Sie Destruktoren von abgeleiteten Klassen diese Möglichkeit, um sicherzustellen, dass die base class Destruktoren virtuell sind?
- Könnten das auch tun
static_assert(std::has_virtual_destructor<Parent>::value, "contract violated");
- Beachten Sie, dass es nicht immer eine Voraussetzung, dass die Basis-Klasse Destruktor virtuell sein. Das ist also nur (eventuell) eine gute Idee, wenn das ist eine Voraussetzung.
- Wenn es funktioniert, wie ich es mag, aber milleniumbug ist besser (viel deutlicher Absicht). Auf der anderen Seite, Stroustrup hasst "coding standard" - Konstrukte, die Wache gegen gemeinsame Fehler, und beharrt darauf, dass der compiler generieren soll geeignete Warnungen, statt.
- Ich denke, @milleniumbug Ansatz drückt die Absicht klar. Wenn stieß ich auf
~Child() override = default;
in einer code-Basis könnte ich einfach die Zeile entfernen. - Gut, mit static_assert erfordert die gleiche Menge an Programmierer Disziplin als mit virtuellen Destruktor, also bin ich nicht sicher, wie man besser ist als andere.
- Ich bin verwirrt. Der Punkt, der
override
--die nur point--ist, Sie zu zwingen, zu einem compiler-Fehler, wenn die Eltern die Methode nichtvirtual
. Wie ist einstatic_assert
eine Verbesserung? - Es hängt davon ab, wie Sie es verwenden. Es ist eine Anforderung, die in einigen Fällen (wenn Sie arbeiten mit Zeigern auf Basisklasse).
- Nur, wenn Sie Sie löschen, sagte Zeiger. Jedenfalls denke ich, dass ich falsch verstanden, das Ende Ihrer Frage.
- Die static_assert werden könnte, gelegt in eine cpp-Datei, die macht es bequemer, um es hinzuzufügen, ohne dass eine Neukompilierung - und auch ausblenden, es als eine Implementierung detail. Doch, das würde es schwieriger machen, zu finden - und der Nachteil mit static_assert ist, dass Sie müssen wiederholen Sie den name der Basis-Klasse; in der Erwägung, überschreiben Sie nur die minimal benötigten Informationen.
- Lieber die
static_assert
scheint wie Wahnsinn. Wenn stieß ich auf denstatic_assert
version, ich würde es ersetzen mitoverride
; das ist der Punkt, deroverride
, in der Erwägung, dassstatic_assert
ist nur verwirrend und nicht-idiomatische Weg, um zu versuchen zu schreiben, in verbose Schutz gegen Schießen selbst in den Fuß. Jede Zeile code ist eine Haftung, insbesondere nicht-idiomatische und verwirrend lieben. - IYAM, wenn man mit jemandem zufällig zu entfernen
virtual
ness der Destruktor in Ihre base-Klasse, Sie haben größere Probleme zu bewältigen (siehe "Vertrag verletzt" - Meldung). Und wenn eine third-party Bibliothek ist dabei, dass, oh boy. - Richtig, beide Konstrukte sind nur Möglichkeiten, verursachen Fehler bei der Kompilierung, wenn etwas passiert, dass wirklich wirklich wirklich sollte nicht passieren. Aber das hat auch nicht wirklich erklären, warum die weniger idiomatischen ein, die anhand komplizierter Typ-trait-Reflexion, ist vorzuziehen.
- die
static_assert
sagt Ihnen genau, was erforderlich ist, und ist vollkommen idiomatisch. Wenn static_assert führt zu Verwirrung, kann es sich lohnen sich etwas Zeit nehmen, um zu studieren, etwas C++. Die andere option sieht mir zu sehr nach redundanten code. - "es kann sich lohnen, nehmen Sie sich etwas Zeit und studieren einige C++" - finden Sie in "die Schuld der Programmierer" am Ende des diesem post. Beachten Sie auch, dass ich nicht wirklich sagen, dass ich nicht verstehe, die
static_assert
nur, dass es mehr verwirrend als dieoverride
version. Das ist wahr, denn es ist länger, Ausführlicher, und verwendet eine vergleichsweise obskure Funktion der standard-Bibliothek. - Der Punkt ist, dass die Prüfung für virtualness der Basis-Destruktor ist nicht die Verantwortung der abgeleiteten Klasse. Es ist eine Verantwortung für diejenigen, die wirklich ein base-Pointer auf abgeleitete Klassen von Objekten und Aufruf
delete
auf Sie. - Zu aufwändig: wenn Sie über 30 abgeleitete Klassen, werden Sie versehen alle von Ihnen? Nein? Gut. (Seite Bemerkung:
std::unique_ptr
ist ein ausgezeichneter Ort, um dies zu überprüfen, aber ich glaube nicht, dass ein solcher check erforderlich ist standard) - Ich Stimme nicht aus einer design-Perspektive. Klassen sollten so ausgelegt sein, dass Sie
delete
d sicher von a Cursor an eine beliebige Stelle in der Hierarchie der Klasse; überprüfung, ob die Klasse war richtig, in dieser Art gestaltet ist, sollte nicht die Sorge des Programmierers, da sollten wir erwarten, dass der Unterricht gut gestaltet. (Dies ist der Punkt, von Klassen-zu unterteilen, das problem des Raumes in der diskreten design-Probleme). - Ich bin allerdings der Meinung, dass der compiler sollte eine Warnung ausgeben, wenn ein base class pointer ist aus einer abgeleiteten Klasse die Basisklasse destructor ist nicht
virtual
, denn dies ist der erste Schritt in die falschedelete
situation. Ich kenne leider kein compiler tatsächlich implementiert diese option Warnung. - Und, wieder, dein Einwand über Anmerkungen 30 abgeleiteten Klassen gilt für beide Konstrukte (
override
undstatic_assert
) gleich gut, und nicht alle zeigen, dass man der anderen vorgezogen (obwohl es sicherlich ein argument gegen so eine Anmerkung als eine Regel-of-Daumen ist wie die Frage fragt). - "Jeder weiß, dass die desructor der Basis-Klasse in der Regel werden virtuelle." Ehm Nein nicht wirklich
- Sind Sie auf den Einwand "jeder weiß" oder "in der Regel werden virtuelle"? (Oder beide?)
- Die letzteren, etwa als eine Folge der ersteren.
- Ich bin nicht sicher, wie ein static_assert, dass explizit verlangt die Basisklasse einen virtuellen Destruktor ist eher verwirrend als das deklarieren einen Destruktor in der Klasse, wenn Sie gar nicht benötigen, nur so können Sie die gleiche Sache. Und es dauert etwa drei Sekunden, um zu erklären, die static_assert zu jeder kompetente Programmierer, der findet, dass festure verschleiern in keiner Weise.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ja, es ist richtig. Auf jeder vernünftige compiler, wenn der code ohne Fehler kompiliert wird, ist diese definition Destruktor wird eine no-op: seine Abwesenheit muss sich nicht ändern, das Verhalten des Codes.
Es ist eine Frage der Präferenz. Für mich macht es nur Sinn, wenn die Basis-Klasse Typ Vorlagen: es erzwingt einen Anspruch auf die Basisklasse einen virtuellen Destruktor, dann. Ansonsten, wenn der base-Typ festgelegt ist, würde ich überlegen, einen solchen code zu Rauschen. Es ist nicht so, wenn die Basisklasse wird magisch ändern. Aber wenn Sie deadheaded Teamkollegen, die, wie die Dinge zu ändern, ohne zu überprüfen, der code hängt davon ab, was Sie eventuell zu brechen, es ist am besten, lassen Sie den Destruktor definition - als eine zusätzliche Schicht von Schutz.
override
ist nichts anderes als ein Sicherheitsnetz. Destruktor der abgeleiteten Klasse wird immer virtuell sein, wenn die Basis-Klasse Destruktor virtuell ist, egal wie man es deklariert oder auch nicht deklariert haben (also implizit deklariert werden).Gibt es (mindestens) einen Grund für die Verwendung
override
hier -- stellen Sie sicher, dass die Basis-Klasse der Destruktor immer virtuell. Es wird ein Kompilierungsfehler, wenn die abgeleitete Klasse einen Destruktor glaubt, es ist etwas überschreiben, aber da gibt es nichts zu überschreiben. Es gibt Ihnen auch ein bequemer Platz zu verlassen generierte Dokumentation, wenn Sie tun, dass.Auf der anderen Seite ich denken kann zwei Gründe dies nicht zu tun:
Wenn Sie definieren eine destuctor in den header (oder wenn du es inline), Sie stellen die Möglichkeit für ungerade Kompilierungsfehler. Lassen Sie uns sagen, dass Ihre Klasse sieht wie folgt aus:
Werden Sie wahrscheinlich einen compiler-Fehler, da der Destruktor (das ist inline mit der Klasse hier) suchen für den Destruktor für die unvollständige Klasse
derived::impl
.Dies ist meine Runde-über die Art zu sagen, dass jede Zeile code, können zu einer Haftung, und vielleicht ist es am besten, überspringen Sie einfach etwas, wenn es funktional nichts tut. Wenn Sie wirklich, wirklich brauchen, um zu erzwingen, einen virtuellen Destruktor in der Basisklasse, von der übergeordneten Klasse, jemand schlug die Verwendung
static_assert
im Konzert mitstd::has_virtual_destructor
, die mehr produzieren, konsistente Ergebnisse, IMHO.Denke ich "override" ist irgendwie irreführend auf Destruktor.
Wenn Sie überschreiben die virtuelle Funktion, die Sie ersetzen.
Die Destruktoren sind angekettet, so dass Sie nicht überschreiben Destruktor buchstäblich
~Derived() override = default;
Mit überschreiben ist die einzige Möglichkeit zur Gewährleistung der Basis-Klasse war richtig definiert. Dies ist besonders wichtig bei der Deklaration von templates, die Ableitung von einem template-parameter, und müssen garantieren, dass die base richtig erklärt, der Destruktor.Den CPP-Referenz sagt, dass
override
stellt sicher, dass die Funktionvirtual
und dass es in der Tat überschreibt eine virtuelle Funktion. Also dieoverride
keyword-würde sicherstellen, dass der Destruktor virtuell ist.Wenn Sie angeben
override
aber nicht= default
, dann erhalten Sie ein linker-Fehler.Brauchen Sie nicht, etwas zu tun. Verlassen der
Child
dtor undefiniert, funktioniert Prima:Wird die Ausgabe
dtor
. Wenn Sie entfernen dievirtual
beiParent::~Parent
wird es aber keine Ausgabe erhalten haben, denn das ist Undefiniertes Verhalten, wie bereits in den Kommentaren.Guter Stil wäre es nicht zu erwähnen
Child::~Child
überhaupt. Wenn Sie nicht darauf Vertrauen können, dass die Basisklasse deklariert virtuelle, dann ist dein Vorschlag mitoverride
und= default
arbeiten; ich würde hoffen, dass es bessere Möglichkeiten gibt um sicherzustellen, dass statt littering Ihrem code, mit denen Destruktor Erklärungen.virtual
beiParent::~Parent
Sie haben Undefiniertes Verhalten. Es könnte Ausgabe nichts. Es kann ein fataler Fehler-dialog. Oder überschreiben der Daten-Datei mit dem Sie arbeiten.Entsprechend der CppCoreGuidelines C. 128 der Destruktor der abgeleiteten Klasse nicht deklariert werden
virtual
oderoverride
.Obwohl Destruktoren werden nicht vererbt, es ist klar geschrieben in der Norm, dass virtuelle Destruktoren von abgeleiteten Klassen überschreiben Destruktoren von Basisklassen.
Aus der C++ - Standard (10.3 Virtuelle Funktionen)
Auf der anderen Seite gibt es auch schriftliche (9.2 Klasse)
Wenn Destruktoren aufgerufen werden, wie spezielle Mitglieds-Funktionen, doch Sie sind auch member-Funktionen.
Ich bin sicher, dass der C++ - Standard geändert werden soll so, dass war es eindeutig, ob ein Destruktor möglicherweise virt-Planer
override
. Es ist derzeit nicht klar.override
. Sie haben geschrieben, Ihre base-Klasse mit einem nicht-virtual
Destruktor; der Compiler richtig verhält.