rule of five und virtual destructor
-
Die "Rule of three" bzw mittlerweile die "rule of five" sagt mir in Kurzform "alle" oder "keinen"
Also ich hab eine Basisklasse in der ich eigentlich nicht spezielles mache und lasse deshalb alle Konstruktoren, Destruktor, Zuweisungsoperator weg.
Da dies aber nun eine Basisklasse ist sollte man ja einen virtuellen Destruktor haben. (Sagt mir auch mein Resharper)
Füge ich den ein:
virtual ~MyBaseClass() =default;
sagt mir dann wiederum der Resharper dass ich dann auch alle anderen ctors usw. implementieren soll.
Ist das richtig? Sehe aber keine Notwendigkeit.
-
Mit Beispiel für eine abstrakte Basisklasse.
-
Das hier steht im Beispiel:
class AbstractBase { public: virtual ~AbstractBase() = default; AbstractBase(const AbstractBase&) = default; AbstractBase& operator=(const AbstractBase&) = default; AbstractBase(AbstractBase&&) = default; AbstractBase& operator=(AbstractBase&&) = default; };
- Bei einer abstrakten Klasse sollte ich doch aber den destructor als pure virtuell definieren
- Muss ich in all meinen Interfaces (Was in c++ ja nur ein typedef auf struct ist) immer die komplette Palette da rein schreiben. Macht die Sache extrem unübersichtlich.
-
@booster sagte in rule of five und virtual destructor:
- Bei einer abstrakten Klasse sollte ich doch aber den destructor als pure virtuell definieren
Nein.Welcher Destruktor soll denn dann aufgerufen werden?
Was in c++ ja nur ein typedef auf struct ist
Was?
-
@manni66 sagte in rule of five und virtual destructor:
@booster sagte in rule of five und virtual destructor:
- Bei einer abstrakten Klasse sollte ich doch aber den destructor als pure virtuell definieren
Nein.Welcher Destruktor soll denn dann aufgerufen werden?
??
@booster
Schon richtig, der Destruktor sollte bei einer abstrakten Klassen (im Sinne von sowas wie Java-Interface) pure virtual sein.
-
@jockelx sagte in rule of five und virtual destructor:
@manni66 sagte in rule of five und virtual destructor:
@booster sagte in rule of five und virtual destructor:
- Bei einer abstrakten Klasse sollte ich doch aber den destructor als pure virtuell definieren
Nein.Welcher Destruktor soll denn dann aufgerufen werden?
??
@booster
Schon richtig, der Destruktor sollte bei einer abstrakten Klassen (im Sinne von sowas wie Java-Interface) pure virtual sein.Edit:
Oder besser etwas defensiver formuliert: 'kann' statt 'sollte'. Sobald du eine pure virtual function hast, brauch der destructor ja nicht mehr pure virtual sein.
-
@jockelx sagte in rule of five und virtual destructor:
Schon richtig, der Destruktor sollte bei einer abstrakten Klassen (im Sinne von sowas wie Java-Interface) pure virtual sein.
Naja, er muss aber trotzdem definiert sein. Wie soll man sonst destructen können? Also
~Class() = 0
ohne alles geht nicht.Also
struct A { virtual ~A() = 0; }; // A::~A() = default; struct B : A {}; int main() { B b; }
kompiliert zwar, linkt aber nicht, weil ~A fehlt. Man muss die kommentierte Zeile schon einkommentieren, damit es geht.
-
@wob sagte in rule of five und virtual destructor:
Naja, er muss aber trotzdem definiert sein. Wie soll man sonst destructen können? Also
~Class() = 0
ohne alles geht nicht.Äh, ja, steht irgendwo was anderes? Oder übersehe ich gerade was?
-
@jockelx sagte in rule of five und virtual destructor:
@manni66 sagte in rule of five und virtual destructor:
@booster sagte in rule of five und virtual destructor:
- Bei einer abstrakten Klasse sollte ich doch aber den destructor als pure virtuell definieren
Nein.Welcher Destruktor soll denn dann aufgerufen werden?
??
@booster
Schon richtig, der Destruktor sollte bei einer abstrakten Klassen (im Sinne von sowas wie Java-Interface) pure virtual sein.~Class() = 0
ist pure virtual, wie du es wolltest. Ist aber wie wob sagte, falsch.
Du musstvirtual ~Class() = default
schreiben, da du immer einen dtor brauchst (selbst wenn er default vom Compiler erstellt wird). Wenn du den dtor in einer abgeleiteten KlasseDerived
überschreiben willst, hast du ja das Problem, dass du versuchst,~Derived()
zu überschreiben und nicht~Class
, was natürlich fehlschlägt, da er~Derived()
nicht in der base class findet.
-> virtual, but not pure virtual dtor
-
@unterfliege sagte in rule of five und virtual destructor:
~Class() = 0
ist pure virtual, wie du es wolltest. Ist aber wie wob sagte, falsch.Ist heute Vollmond?
Das ist nicht falsch und hat wob auch nicht gesagt. Muss halt noch definiert werden; hab ich aber auch nie gesagt, dass man das nicht muss.
-
Was ich nur sagen wollte: Die Intention von ~Class() = 0; ist NICHT, dass der Destruktor pure virtual ist (das ergibt ja keinen Sinn, da man sonst Objekte nicht zerstören könnte), sondern dass die Klasse pure virtual wird. Es ist nur ein syntaktisches Mittel zum Zweck.
-
@jockelx Unter pure virtual destructor verstehe ich lediglich einen dtor, der noch in der abgeleiteten Klasse definiert werden muss. Und das ist, wie erklärt, nicht möglich.
Und ja, wenn man den "pure virtual dtor" noch definiert, funktioniert es. Ich suche nur den Sinn dahinter und wieso das deiner Meinung nach so gemacht werden sollte. Ein einfacher virtual dtor ist vollkommen ausreichend.
Wenn das nur genutzt werden soll, um eine ansonsten vollständige Klasse pure virtual zu machen, sehe ich eher einen Designfehler.
-
@unterfliege sagte in rule of five und virtual destructor:
Ich suche nur den Sinn dahinter und wieso das deiner Meinung nach so gemacht werden sollte. Ein einfacher virtual dtor ist vollkommen ausreichend.
Ich hatte mein 'soll' direkt in ein 'kann' geändert. Richtig, ein virtual dtor reicht völlig aus, wenn du eine abstrakte Klasse willst und zumindest irgendeine pure virtual function hast.
Wenn das nur genutzt werden soll, um eine ansonsten vollständige Klasse pure virtual zu machen, sehe ich eher einen Designfehler.
Ja, das ist der Grund. Das das ein Designfehler ist, ist deine Ansicht. Schreib Scott Meyers, dass sein Kapitel über virtuelle Destruktoren scheisse ist; ich bin hier raus.
-
Das mit dem virtuellen Destruktor war mir klar.
Meine Frage zielt eigentlich auf die Konstruktoren und die Zuweisungsoperatoren ab.
-
Also egal ob ich den Destruktor nun virtuell oder abstract mache.
Wenn ich nen Destruktor habe soll ich nach der "rule of five" auch alle anderen copy und move operations implementieren.
Was ich bei einem interface (abstracte basisklasse) als total unübersichtlich finde.
-
@Unterfliege sagte in rule of five und virtual destructor:
~Class() = 0 ist pure virtual, wie du es wolltest. Ist aber wie wob sagte, falsch.
Nö, ist nicht falsch, nur redundant.
"Pure" (
= 0
) heisst nur dass die Funktion in einer abgeleiteten Klasse überschrieben werden muss wenn sie instanzierbar sein soll. Da Destruktoren aber sowieso implizit definiert werden wenn man sie nicht explizit definiert, wird ein virtueller Destruktor einer Basisklasse immer überschrieben. Womit das "pure" halt grösstenteils nutzlos wird.
(Es gibt einen Anwendungsfall den ich kenne wo es Sinn machen kann, und das ist wenn man eine Klasse abstrakt machen will, aber keine "normale" Funktion "pure" machen will. Der Destruktor bietet sich dann an, gerade weil er ggf. implizit definiert und damit immer überschrieben wird.)Was bei "virtual pure" Destruktoren zu beachten ist, was @wob schon angesprochen hat, ist dass man sie trotzdem definieren muss. Da sie ja auch aufgerufen werden (als Teil der Zerstörungsprozesses des Objekts der abgeleiteten Klasse.) Und da das Definieren von "pure" Funktionen nicht verboten ist, kann man das auch machen. (Es ist nur umgekehrt - bei normalen Funktionen - erlaubt die Definition wegzulassen. Man muss sie aber nicht weglassen.)
-
@hustbaer sagte in rule of five und virtual destructor:
Nö, ist nicht falsch, nur redundant.
Ja ich weiß.
Ist ja nur ein Hilfsmittel um eine Klasse als Abstract zu kennzeichnen wenn sie sonst keine Member hat die man als rein virtuell kennzeichnen kann.
Aber nochmals was ist mit den copy und move operations?
-
@booster sagte in rule of five und virtual destructor:
Ist ja nur ein Hilfsmittel um eine Klasse als Abstract zu kennzeichnen wenn sie sonst keine Member hat die man als rein virtuell kennzeichnen kann.
Aber nochmals was ist mit den copy und move operations?
Copy und move-Zeugs musst du nicht definieren wenn du den Dtor eh als= default
implementierst.
Die Regel existiert ja nur weil es wahrscheinlich ist dass, wenn man in einem der grossen 5 etwas anderes macht als default wäre, in den restlichen 4 vermutlich auch etwas anderes braucht. Da= default
aber nix anders macht als default...
Ich würde einfach mal sagen die Warning sollte bei= default
vermutlich überhaupt nicht anschlagen.EDIT: Siehe Korrekturen weiter unten.
-
@hustbaer sagte in rule of five und virtual destructor:
Copy und move-Zeugs musst du nicht definieren wenn du den Dtor eh als = default implementierst.
AFAIK gilt das als benutzerdefinierter Destruktor und verhindert somit das automatische Erzeugen von Move.
-
@hustbaer sagte in rule of five und virtual destructor:
Ich würde einfach mal sagen die Warning sollte bei = default vermutlich überhaupt nicht anschlagen.
Jo das wäre eigentlich korrekt. Aber resharper zeigt halt trozdem eine. Blöd
-
Die Warnung weißt sogar darauf hin das der destructor default ist.
class '...' defines a default destructor but does not define a copy constructor, a copy assignment operator, a move constructor or a move assignment operator