virtueller destruktor
-
dot schrieb:
this->that schrieb:
Das kann ich als Erzeuger der Basisklasse doch meistens garnicht wissen.
Doch. Wenn du eine Basisklasse schreibst dann weißt du doch für was die gedacht ist
Ja. Zum vererben.

dot schrieb:
immerhin bist du dort auf der selben Abstraktionsschicht wie der Code der sie verwendet (wenn nicht dann verwendest du Vererbung grad falsch). Und in den entsprechenden Fällen wirst du den Destruktor protected machen, damit ist es unmöglich Objekte über einen Basisklassenzeiger zu deleten...
Habe ich in der Praxis noch nicht ein einziges mal gesehen. In 99% der Faelle schreibst du virtual, weil das Ding ne Basisklasse wird und andere davon ableiten sollen und es nahezu immer Sinn macht, die Moeglichkeit einzuraeumen ueber Basisklassenzeiger zu loeschen.
-
this->that schrieb:
dot schrieb:
this->that schrieb:
Das kann ich als Erzeuger der Basisklasse doch meistens garnicht wissen.
Doch. Wenn du eine Basisklasse schreibst dann weißt du doch für was die gedacht ist
Ja. Zum vererben.

Nur ein verschwindend geringer (man könnte fast sagen vernachlässigbarer) Teil meiner "Basisklassen" dient wirklich als Basisklasse in dem Sinne dass andere Klassen etwas davon erben (ich bin mit solche Klassen bewusst sehr sparsam). Der Großteil sind einfach nur rein abstrakte Interfaces. Der Code der diese Interfaces verwendet ist vollkommen losgelöst vom Code der die Objekte erzeugt die diese Interfaces implementieren. Der Code der die Objekte erzeugt kennt die aber meistens direkt und nicht nur über ihr Interface. Die Möglichkeit Objekte über Basisklassenzeiger zu deleten braucht man gar nicht so oft wie du vielleicht denkst und wenn dann beschränkt sich das auch auf kleine Bereiche des Codes.
-
dot schrieb:
ein virtueller Destruktor nicht immer notwendig, auch wenn die Klasse eine Basis ist und virtuelle Methoden hat. Ein virtueller Destruktor ist nur dann notwendig wenn über einen Basisklassenzeiger deleted werden soll.
Ich verstehe nicht, wozu die Basis virtuelle Funktionen hat, wenn Sie sowie nicht über einen Basiszeiger angesprochen werden kann.
-
dot schrieb:
this->that schrieb:
dot schrieb:
this->that schrieb:
Das kann ich als Erzeuger der Basisklasse doch meistens garnicht wissen.
Doch. Wenn du eine Basisklasse schreibst dann weißt du doch für was die gedacht ist
Ja. Zum vererben.

Nur ein verschwindend geringer (man könnte fast sagen vernachlässigbarer) Teil meiner "Basisklassen" dient wirklich als Basisklasse in dem Sinne dass andere Klassen etwas davon erben (ich bin mit solche Klassen bewusst sehr sparsam). Der Großteil sind einfach nur rein abstrakte Interfaces. Der Code der diese Interfaces verwendet ist vollkommen losgelöst vom Code der die Objekte erzeugt die diese Interfaces implementieren. Der Code der die Objekte erzeugt kennt die aber meistens direkt und nicht nur über ihr Interface. Die Möglichkeit Objekte über Basisklassenzeiger zu deleten braucht man gar nicht so oft wie du vielleicht denkst und wenn dann beschränkt sich das auch auf kleine Bereiche des Codes.
Naja, letztlich braucht man es nur dann nicht, wenn die Erzeugung und Zerstoerung zentralisiert (z.B. ueber eine Factory) stattfindet.
Es ist auf jeden Fall nicht der Standardfall, denn das ist ja gerade einer DER Pluspunkte von Vererbung, dass du gegen ein Interface programmierst und nicht wissen musst wie die Implementierung aussieht und auch das Loeschen automatisch klappt.
Ich bleibe auf jeden Fall bei meiner Faustregel=)
-
Jockelx schrieb:
Ich verstehe nicht, wozu die Basis virtuelle Funktionen hat, wenn Sie sowie nicht über einen Basiszeiger angesprochen werden kann.
"Ansprechen" ist was andres als das Objekt deleten...
-
this->that schrieb:
Es ist auf jeden Fall nicht der Standardfall, denn das ist ja gerade einer DER Pluspunkte von Vererbung, dass du gegen ein Interface programmierst und nicht wissen musst wie die Implementierung aussieht [...]
Naürlich. Aber wie gesagt: Der Code der das abstrakte Interface verwendet ist normalerweise losgelöst vom Code der die Objekte erzeugt und zerstört.
this->that schrieb:
Naja, letztlich braucht man es nur dann nicht, wenn die Erzeugung und Zerstoerung zentralisiert (z.B. ueber eine Factory) stattfindet.
Beispiel:
Ich hab mein 3D Spiel und da hab ich eine Klasse
Scenedie eben meine 3D Szene darstellt. Und in diese Szene kann ich jetztSceneObjects (ein Interface) einfügen. Nun erzeugt meine Spiellogik Objekte die auch eine graphische Repräsentation haben sollen. Diese Objekte erzeugen (oder bekommen) ihrerseits die entsprechenden Grafikobjekte die alleSceneObjects sind und dann in dieSceneeingefügt werden. Aber meine KlassePlayerweiß dass sie einAnimatedModelhat und kennt dieses nicht nur alsSceneObject. Anders gehts sogar garnicht da diePlayerKlasse ja die Animationen abspielen muss und dafür reicht ein allgemeinesSceneObjectnicht. Wer auch immer dasAnimatedModelerstellt zerstört es auch wieder und tut dies über den konkreten Typ und nicht über das Interface. Wenn man mit Dependency Injection arbeitet ergeben sich meiner Erfahrung nach eigentlich immer solche Strukturen. Das hat nichts mit zentralen Factories zu tun sondern einzig mit der Tatsache dass man den konkreten Typ kennen muss um ein Objekt zu erzeugen. Natürlich gibt es auch Fälle wo man über Basiszeiger deleten will, aber die sind meiner Erfahrung nach bei weitem nicht so häufig wie man vielleicht denken mag.
-
Hilft mir ehrlich gesagt nicht:
SceneObject ist jetzt die Basisklasse mit virtuellen Funktionen und protected Destruktor?
Und AnimatedModel ist eine Ableitung davon?
Und was ist jetzt der Vorteil davon (statt 'normalem' virtuellen Destruktor)?
-
Jockelx schrieb:
SceneObject ist jetzt die Basisklasse mit virtuellen Funktionen und protected Destruktor?
ja z.B.
Jockelx schrieb:
Und AnimatedModel ist eine Ableitung davon?
ja
Jockelx schrieb:
Und was ist jetzt der Vorteil davon (statt 'normalem' virtuellen Destruktor)?
Es geht nicht um irgendeinen Vorteil sondern darum zu demonstrieren dass hier nirgendwo über Basiszeiger deleted werden muss. Der der das Objekt erzeugt hat zerstört es auch wieder und er kennt das Objekt beim konkreten Typ und nicht nur über den Basiszeiger. Und das Beispiel ist jetzt nicht gerade an den Haaren herbeigezogen, sowas hat man eigentlich ziemlich oft. Gerade eine Factory ist eigentlich die einzige Möglichkeit Objekte zu erzeugen ohne ihren konkreten Typ zu kennen.
-
Mmh? Das ist doch gar nicht die Frage, dass man nicht immer über den Basiszeiger deleten muss.
Das Problem ist doch, dass man deine SceneObjects nie über den Basiszeiger deleten kann.Und da frage ich mich: wo brauch man das?
-
Jockelx schrieb:
Das Problem ist doch, dass man deine SceneObjects nie über den Basiszeiger deleten kann.
Du siehst es falsch rum. Es macht keinen Sinn ein SceneObject über den Basiszeiger zu deleten und soll daher auch nicht möglich sein. Das Interface dient nur dazu verwendet zu werden. Die Verwaltung der konkreten Objekte passiert wo anders. Code der mit SceneObject arbeitet soll sich nicht darum kümmern was für konkrete Objekte dahinterstehen und wie sie erzeugt wurden. Dafür sind andere zuständig. Überleg mal was es genau bedeutet wenn du Code hast der ein Objekt über einen Basisklassenzeiger deleted. Damit sagst du: "Ich weiß zwar nicht was für ein Objekt das genau ist aber es muss mit new erzeugt worden sein"...
Wenn ich sowas mach dann will ich sichergestellt haben dass solche Objekte nur mit new erzeugt werden können. In dem Fall verwend ich normalerweise folgendes Pattern:class MyObject { protected: MyObject() {} ~MyObject() {} public: virtual void DoSomething() = 0; virtual void Release() = 0; } class MyConcreteObjectA : public MyObject { private: MyConcreteObjectA() {} ~MyConcreteObjectA() {} public: static MyConcreteObjectA* create() { return new MyConcreteObjectA(); } void DoSomething() { ... } void Release() { delete this; } }Und da brauch ich erst recht keinen virtuellen Destruktor

-
Nee, das legst du mir jetzt aber in den Mund, dass ich deine Interface-Struktur aufbrechen will.
Aber okay, so langsam verstehe ich dein Beispiel.
Du verhinderst mit deinem Design, dass man deine Interface-Struktur überhaupt aufbrechen kann.
Okay, das ist vielleicht ganz gut. Andererseits darf so jemand auch gerne damit auf die Fresse fallen, wenn er fröhlich Pointer deleted, die er über eine Interface-Funktion kriegt.Dankeschön, war ganz interessant. Auch wenn du mich nicht überzeugen konntest, das zukünftig so zu machen.