Verschiedene Objekte in einem Vektor
-
Artchi schrieb:
class Basis { public: virtual void foo(); }; class Abgeleitet : public Basis { public: void foo(); // foo nur optional, wenn es neu implementiertt werden soll. }; vector<Basis*> pVector; pVector.push_back( new Basis() ); pVector.push_back( new Abgeleitet() ); // pVector.at(0)->foo(); // ruft foo von Basis auf pVector.at(1)->foo(); // ruft foo von Abgeleitet aufWarum willst du also casten? Ist nicht der Sinn von Polymorphie. Man braucht eigentlich nur in Ausnahmefällen casten.
Vieleicht will er sowas machen
class Basis { public: virtual void foo(); }; class Abgeleitet : public Basis { public: void foo(); // foo nur optional, wenn es neu implementiertt werden soll. void bar(); }; vector<Basis*> pVector; pVector.push_back( new Basis() ); pVector.push_back( new Abgeleitet() ); // pVector.at(0)->foo(); // ruft foo von Basis auf pVector.at(1)->foo(); // ruft foo von Abgeleitet auf pVector.at(1)->bar(); // wird nicht gehen... dynamic_cast<Abgeleitet*>(pVector.at(1)->bar()); // wird gehenDie Frage die sich mir jetzt stellt ist, wie kann man herausfinden das es sich in Wahrheit um einen Zeiger auf die Abgeleitete Klasse handelt? Ich würde jetzt pauschal sagen das das gar nicht geht und das dies ein Zeichen für einen Designfehler ist. Berichtigt mich wenn ich falsch liege.
-
Ja, genau das ist das Problem:
pVector.at(1)->bar(); // wird nicht gehen...Bei dem oben beschriebenem Problem beginne ich an zu "casten". Finde ich aber persönlich nicht sauber gelöst.
Die Frage die sich mir jetzt stellt ist, wie kann man herausfinden das es sich in Wahrheit um einen Zeiger auf eine Abgeleitete Klasse handelt?
Ich habe ein ENUM-Wert in "public" in der Basisklasse.
Ich würde jetzt pauschal sagen das das gar nicht geht und das dies ein Zeichen für einen Designfehler ist. Berichtigt mich wenn ich falsch liege.
Wahrscheinlich hast du recht. Wie würdest du vorgehen? Mein Prinzip war bisher die Baumstruktur. Eine Basisklasse pro "Baum" von der dann weitere Klassen abgeleitet werden. Aber im Vergleich zu einem Baum werden die Äste immer dicker je weiter man vom Stamm entfernt ist. Mmmh...

-
Es kommt halt drauf an "was" deine Klassen machen müssen und ob es nicht sinnvoll ist andere std::vector'en für die Speicherung zu benutzten. Ich stand auch mal vor dem gleichen Problem, weil ich die Zeiger, auf alle Steuerelemente meines Dialogs, speichern wollte. Ich weis jetzt aber nicht wieso
. Am ende hab ich verschiedene vector'en genommen.
-
Sinn der Polymorphie ist es, Klassen so zu abstrahieren, das man unterschiedliche Implementationen gleich behandeln kann .... der anwender (client) gar keine ahnung hat was genau er da hat, sondern sich einfach drauf verlaesst das das ding schon alles richtig macht. (schnittstellen prinzip)
Was aber wenn die abgeleitete Klasse neue Methoden einführt...
und Du diese methode auch noch brauchst, dann ist deine abstraktion ned komplett. Du brauchst mehr informationen als deine schnittstelle bietet, Schnittselle ungeeignet.
- Entweder erweiterst die Schnittstelle, und paar ableitungen bekommen funktionen verpasst die eigentlich nichts machen ...
- oder du kannst deine unterschiedlichen typen ned vereinheitlichen, weil einmal arbeitest eben mit normalen "windos", und einmal mit childs windows, wenn deren spezielle funktionalitaet brauchst. Dann solltest alle child windows in nem eigenen container referenzieren z.b. und ned mit den nichtchilds in einen sack werfen.Ciao ...
-
Wie einige hier schon sagten, die Basis gibt ein Interface vor. Wenn du es in einem Container speicherst, geht der Benutzer davon aus bzw. du gehst davon aus, das er auch nur dieses INterface braucht. Was man machen könnte, ist einen zweiten Container anlegen, der die Pointer verwaltet, die für abgeleitete Klassen gültig ist.
Beispiel:
vector<Basis*> basis_vec; vector<Abgeleitet*> abgeleitet_vec; basis_vec.push_back( new Basis() ); Abgeleitet *a = new Abgeleitet() basis_vac.push_back( a ); abgeleitet_vec.push_back( a);So, wenn der Benutzer eh weiß, das er die Methode bar() aufrufen will, dann weiß er ja auch, das es diese nur in "Abgeleitet" gibt. Richtig? Richtig! Also kann er auf den entsprechenden Vector zugreifen. Wer nur Basis-Interfaces benutzt, entsprechend den altbekannten Vector.
Aber meistens ist es ja so, das man z.B. ein Flugzeug starten, landen, oder nach rechts fliegen lassen will. Egal ob es ein Jumbojet oder eine einmotorige Einsitzermaschine ist... das Interface ist in der Basis-Klasse definiert. Wenn ich aber Racketen abfeuern will, habe ich natürlich ein Problem. Aber weißte was? Dann mache ich mir eine andere Basis-Klasse "Kampfflugzeug" die von Flugzeug abgeleitet ist. Und mache einen zweiten Vector dafür.
-
Ja, verstehe. Werd' mir also einen neuen Ansatz überlegen.
Was würdet ihr machen um in einem zwei -oder mehrdimensionalem Raum (z.B. ein zweidimensionaler Vektor) Objekte zu speichern die unterschiedlichen Klassen entstammen?
-
goran schrieb:
Ja, verstehe. Werd' mir also einen neuen Ansatz überlegen.
Was würdet ihr machen um in einem zwei -oder mehrdimensionalem Raum (z.B. ein zweidimensionaler Vektor) Objekte zu speichern die unterschiedlichen Klassen entstammen?Was machen deine Klassen eigentlich? Und warum musst du verschiedene Kinder davon in einem (2 dimensionalen) vector speichern?
-
goran schrieb:
...
Was würdet ihr machen um in einem zwei -oder mehrdimensionalem Raum (z.B. ein zweidimensionaler Vektor) Objekte zu speichern die unterschiedlichen Klassen entstammen?Hi,
ich weiß zwar nicht, ob ich Dich so ganz richtig verstehe, aber mir scheint, dass es Dir bei "Raum" um einen "fachlichen Raum" (z.B. 2D-Fläche, 3D-Raum oder auch andere fachliche Größe) handelt.
Das mag in dem Fachgebiet eine geeignete Modellierung sein, aber in der Programmierung würde ich nicht den Raum beschreiben, sondern die Objekte ... und ihre "Position" im gewünschten Raum einfach als Attribute. So kann jedes Objekt einen "Ort", einen "Widerstand", eine Farbe, .... besitzen und schon ist er eindeutig im Ort-Widerstands-Farbenraum beschrieben.Langer Rede Kurzer Sinn: Ich würde die Objekte in einem Container (z.B. vector) speichern und gut ist.
Wenn Du die Position eindeutig haben möchtest (was nur bei diskreten Größen gut zu programmieren ist), kannst Du ein std::set nehmen (mit geeignetem Vergleichsoperator auf die Attribute).
Wenn Du partout die "Raumposition auslagern" willst, kannst Du auch eine std::map nehmen. Das hat allerdings den Nachteil, dass Dein Objekt nicht mehr auf seine "Position" zugreifen kann ("es weiß nicht mehr, wo es ist")....// Simpelster Ansatz: Attribute direkt in Klasse enum Farbe { ROT, GRUEN }; struct meinFachobjektImRaum_simpel { int x, y, z; int widerstand; Farbe farbe; double sonstiges Attribut; }; std::set<meinFachobjektImRaum_simpel> fachObjekteImRaum_simpel; // etwas sortierter: Attribute ausserhalb der Klasse gebündelt struct Raumposition { int x, y, z; int widerstand; Farbe farbe; }; struct meinFachobjektImRaum { Raumposition position; double sonstiges Attribut; }; std::set<meinFachobjektImRaum> fachObjekteImRaum; // Alternativ: Position nur über den Container zugeordnet struct meinReinesFachobjekt { double sonstiges Attribut; }; std::map<Raumposition, meinReinesFachobjekt> fachObjekteImRaum;(da muss jeweils noch ein comparator, damit map/set wissen, wann zwei Objekte unterschiedlich sind).
Ach ja Weil es noch nirgends beschrieben wurde: Objekte, die Du mit new/new[]anlegst, musst Du mit delete/delete[] wieder löschen, um Speicherlecks zu verhindern .... das macht der Container nicht für Dich.
Gruß,
Simon2.
-
Was würdet ihr machen um in einem zwei -oder mehrdimensionalem Raum (z.B. ein zweidimensionaler Vektor) Objekte zu speichern die unterschiedlichen Klassen entstammen?
Obs logisch sinn macht, sei mal dahingestellt ... dazu ham die Vorposter schon was gesagt.
Aber in der Praxis kommt so eine Anforderung natuerlich auch ab und an vor.
Das Modell um Schnittstellen anzupassen heisst Adapter (Design Pattern).Sprich ich ueberleg mir ne schnittstelle die alle diese unterschiedlichen Objecte gemeinsam bedienen sollen. dann schreib ich fuer jede zu adaptierende Klasse einen Adapter, der Adapter ist von der Schnittstelle abgeleitet. nu kann man die Objecte quasi gleich behandeln, in die gleichen container werfen etc ...
Ciao ...
-
Nochmal danke Leute.
Das Programmieren ist mir 'noch' nicht ganz ins Blut über gegangen aber es wird schon.

Der Grund warum ich verschiedene Objekte im selben Raum speichern wollte war das ich mich bei meinen Berechnungen in nicht in einem Ring bewege. Also mal Dieses, mal Jenes als Ergebnis da stehen kann. Ich habe den Tag genutzt um mir ein anderes Modell zu überlegen und das wird (meiner Meinung nach) besser zu implementieren sein.
Trotzdem gut' was dazu gelernt.

Grüße
Goran
-
ich möchte hier noch ne frage in den raum werfen, zu dem vorschlag für jede klasse eigene container zu verwenden.
Das funktioniert solange gut, wie man die Vererbungsstruktur feststeht. Aber was ist wenn der Benutzer eigene Klassen von denen der Lib ableitet? Innerhalb der Lib kann man dann ja schlecht zusätzliche Container einfügen. Außer vielleicht mit Typlisten. Ist aber auch nicht immer sinnvoll. Dann komme ich wohl oder übel nicht über dynamic_Cast herum?
-
Dann brauchst du auch keine Polymorphie, wenn du so denkst. Polymorphie heißt auch imemr ein festgelegtes Interface zu bedienen. Du sprichst etwas an, das darauf hinausläuft, das bei jeder neuen Klasse ein total anderes Interface zustande kommt. Dann sage ich dir: lass Ableitungen und somit OO-Features aus deinem Sprachschatz raus.
-
nein, du hast mich falsch verstanden. (oder ich habe es falsch erklärt).
Aber versuche ich mal anhand eines Beispiels:Sagen wir mal, ich schreibe eine Gui-Lib. So mit Fenstern, vielen tollen verschiedenen buttons, usw.
Diese Buttons und andere Controls befinden sich logischerweise innerhalb von Fenstern.
Man kann auch als User der Lib durch alle Steuerelemente, die sich in einem Fenster befinden iterieren. Mal angenommen ich meine Lib unterstüzt auch Bild-Controls, Also steuerelemente, die Bilder enthalten können. Wenn ich darauf zugreife. Kann ich z.b. die Funktion, ImageControl* getImages() aufrufen.Obwohl ich da tausende von steuerelementen erstellt habe, habe ich die Lib auch so geschrieben dass man eigene controls implemnentieren und verwenden kann. So kommt z.b. ein User auf die Idee ein Steuerelement zu programmieren, dass z.b. seinen namen als 3d animation darstellt. so ein steuerelement gibt es ja bei mir nicht.
Entweder könnte er mir jetzt den Quelltext (oder mindenstens den Header) für sein Steuerelement zu schicken. Dann ich dann bei meinem Fenster eine Methode mit dem Namen getNameDisplayControls() schreiben, die dann alle Controls mit diesem Typ zurückgibt, die sich auf dem aktuellen Fenster befinden. (Meine Lib ist closed-source.)
Oder ich mache soetwas nicht und biete einfach die Funktion Control* getControls() an, die einfach alle Steuerelemente zurückgibt. Aber soetwas darf ich ja deiner meinung nach nicht machen. Meiner meinung nach wäre die erste Möglichkeit sinnlos.
Und nein, den Quelltext der Lib will ich nicht veröffentlichen.
-
Dann ist Objektorientierung noch nicht bei dir in Fleisch und Blut übergangen. Ich greife mal dein Beispiel mit der 3D-Darstellung auf. Nichts einfacher als das!
class GuiBasisElement { public: virtual void draw(GrafikContext g); };So, das ist gängige Praxis! Jedes GUI-Element zeichnet sich SELBST. Jedes Element in den Containern wird einfach durch iteriert und die draw-Methode aufgerufen. draw() ist in dem Fall ein Interface-Bestandteil. So, jetzt kommt ein x-beliebiger User aus Asien der sein eigenes neues 3D-Control schreiben will. Was macht er? Er implementiert einfach die draw-Methode!!!!!
class Mein3DControl : public GuiBasisElement { public: virtual void draw(GrafikContext g) { // 3D-Grafikcode zeichnet in den Grafikcontext g. } };Deine Lib, die nichts von Mein3DControl weiß, und auch nichts wissen muß, ruft einfach draw auf. Was draw macht, ist sowas von banane, das glaubt man nicht. Ob jemand jetzt 2D-Grafik zeichnet, 3D-Grafik zeichnet, nichts zeichnet interessiert hier nicht. Du (!) hast eine Schnittstelle für andere Programmierer vorgegeben die sagt: "alles was dein Control darstellt, sollst du bitte in draw implementieren." Punkt!
Damit das Control weiß, wo es hinzeichnen muß, übergibt man ihr einen Context (Zeichenfläche, z.B. einen Fensterbereich).
Auch das hier wäre möglich:
class AppleQuickTimePlayer: public GuiBasisElement { public: virtual void draw(GrafikContext g) { // Bilder des MPEG-Movies darstellen bzw. in den Grafikcontext zeichnen... } };D.h. selbst Movieplayer kann man als GuiElement darstellen. Ist nur eine Frage der Implementierung. Nichts anderes machen z.B. die Plugins für InternetExplorer oder Firefox. Der QuickTime-Player implementiert einfach eine vorgegebene Draw-Schnittstelle, die MS oder Mozilla vorgibt, und schon sieht man einen Movie im Browser ablaufen. Aber IE und Firefox wissen nicht, das es ein Movieplayer ist. Warum auch?
DAS ist Polymorphie.
Deshalb sagen wir hier ja alle: dynamic_cast ist selten nötig! Definiert eine Schnittstelle in euren Basisklassen, und jeder kann diese implementieren. Der spezielle Objekttyp ist irrelevant für die Laufzeit.EDIT:
vector<GuiBasisElement*> controls; controls.push_back( new Mein3DControl() ); controls.push_back( new AppleQuickTimePlayer("C://move.mpg") ); //... for(size_t i =0; i < controls.size(); i++) controls.at(i)->draw( fenster ); // fenster ist ein Grafikcontext
-
ich programmiere schon paar tage (auch objektorientiert), du erzählst mir da nix neues.
Mein beispiel oben war vielleicht nicht so passend, aber ich versuche es nochmal:
Nehmen wir diesmal an, du bist der gui-lib-programmierer (hast ja die klassen schon geschrieben).
Ich programmiere einen AppleQuickTimePlayer:
Im Gegensatz zu deinem, kann man meinen auch von außerhalb steuern:class MeinAppleQuickTimePlayer: public GuiBasisElement { public: virtual void draw(GrafikContext g) { // Bilder des MPEG-Movies darstellen bzw. in den Grafikcontext zeichnen... } void play(); void stop(); void irgendwas(); };Nun will ich aus unerfindlichen Gründen MeinAppleQuickTimePlayer::play() aufrufen. Ich habe aber keinen Zeiger auf MeinAppleQuickTimePlayer gespeichert. Dafür aber das Fenster und ich weiß dass sich im Fenster ein Player befindet.
Wie komme ich nun an MeinAppleQuickTimePlayer ohne dynamic_cast ???
Wenn du meinst, dass so eine situation nie eintritt, dann kannst du bzw. ich noch mehr "funtionalität" in die lib einbauen:
Man kann die Fenster mit steuerelementen als xml-Dateien auf die festplatte laden bzw. speichern. Diese Funktionalität ist nicht sichtbar für den end-user.
d.h. er kann keinen Pointer auf MeinAppleQuickTimePlayer besitzen.
-
Nun will ich aus unerfindlichen Gründen MeinAppleQuickTimePlayer::play() aufrufen. Ich habe aber keinen Zeiger auf MeinAppleQuickTimePlayer gespeichert. Dafür aber das Fenster und ich weiß dass sich im Fenster ein Player befindet.
play kann der jenige aufrufen, der den Player kennt. Oder sich über einen Callback oder Delegate diesen indirekt merkt. Dein Denkfehler ist, das du auf einen Player speziell zugreifen willst, obwohl du ihn nicht kennst. Das ist so, als wenn du in einem Polizeiauto die Sirene einschalten willst, obwohl du garkein Polizeiauto kennst oder vor dir stehen hast. Du willst anscheinend über Magie etwas tätigen, was völlig unmöglich ist.
Wie programmierst du denn normalerweise? Du hast ein spezielles Objekt angelegt (den Player), weil du mit diesem etwas spezielles machen willst. Und du legst diesen in einen Container, der allgemeingültig ist. Du machst den Denkfehler, das du die Fenster-Klasse siehst, was sehr allgeimegültig ist und verwechselst es mit deiner spziellen Klasse. Meistens hat man aber eine spezielle Klasse, die den Kontext kennt (in dem Fall den Player). Und diese spezielle Klasse merkt sich den Player.
Beispiel:
class Anwendung { MeinAppleQuickTimePlayer *player; Fenster fenster; // da ist der allgemeine Container drin public: Anwendung() { player = new MeinAppleQuickTimePlayer(); // speziell fenster.add(player); // allgemein } void foo() { fenster.show(); //zeichnet unter anderem den Player, auch wenn es ihn nicht speziell kennt player->play(); } };Das Fenster kennt zwar nicht die play-Methode, aber du selbst hast doch den Player angelegt und kannst ihn bedienen.
Ich glaube, hier liegt der Irrtum vor, das nur der Container die GUI-Elemente kennen soll.
Wenn es dir darum geht, das der Movieplayer vom User bedient werden soll: der Player kümmert sich selber um seine Play-Buttons. Drückt der User mit der Mouse drauf, reagiert der PlayButton selbst (genauso wie er sich auch selber zeichnet!).
Das sind halt Erfahrungen, die man sammelt. Meistens ist die Sache einfacher und logischer als man denkt.
-
Hier noch ein paar Hinweise, die man sich später mal anschauen sollte:
- Command-Pattern http://de.wikipedia.org/wiki/Command_Pattern
- Function http://www.boost.org/doc/html/function.html (aka Delegates-Pattern)Diese dienen dafür, z.B. play aufzurufen, OHNE den Player speziell zu kennen!!! Aber es ist kein Cast nötig!!!
Würde ich mich aber erst mit beschäftigen, wenn ich etwas mehr Erfahrung mit eigenen "Kreationen" gesammelt habe. Weil dann wird man erst diese Patterns zu schätzen wissen und man erkennt die Probleme die man damit löst.

-
Artchi schrieb:
play kann der jenige aufrufen, der den Player kennt. Oder sich über einen Callback oder Delegate diesen indirekt merkt. Dein Denkfehler ist, das du auf einen Player speziell zugreifen willst, obwohl du ihn nicht kennst. Das ist so, als wenn du in einem Polizeiauto die Sirene einschalten willst, obwohl du garkein Polizeiauto kennst oder vor dir stehen hast. Du willst anscheinend über Magie etwas tätigen, was völlig unmöglich ist.
Wo genau ist da der Denkfehler? Wenn meine Fensterklasse funktionen bietet um über GuiBasisElement* zu itererieren. Was ist daran auszusetzten dass ich so auf den Player dann auch zugreife?
Noch zusätzlich irgenwelche Zeiger zu speichern ist rendundant und kann Fehler verursachen. (Mein Player wird ohne meine Kenntnis durch einen anderen ersetzt.) Natürlich kann ich für alle möglichen Fälle Callbacks und co. anbieten. Aber warum sich unnötig arbeit machen, wenn ein einfacher dynamic_cast ausreicht?Wie programmierst du denn normalerweise? Du hast ein spezielles Objekt angelegt (den Player), weil du mit diesem etwas spezielles machen willst.
Ich habe ja im letzten Absatz geschrieben, dass das Fenster aus einer XML-Datei erstellt wird. Die Xml-Datei wurde mit irgendeinem GUI-Editor angelegt. Ok, ich kann da callbacks beim laden zwischenschalten und so auf einen pointer kommen. aber dazu siehe oberen absatz.
Ich glaube, hier liegt der Irrtum vor, das nur der Container die GUI-Elemente kennen soll.
Wenn es dir darum geht, das der Movieplayer vom User bedient werden soll: der Player kümmert sich selber um seine Play-Buttons. Drückt der User mit der Mouse drauf, reagiert der PlayButton selbst (genauso wie er sich auch selber zeichnet!).
Naja, der Player kann nicht alle Möglichkeiten abdecken, wie ihn der Benutzer verwendet. Der kann auf Player direkt klicken. Ok, den Fall braucht man nicht weiter zu betrachten. Der Player kann hier selbst dafür sorgen, dass er diese Aktionen wahrnimmt.
Aber wenn ich meinen Player übers Netzwerk steuern will. will ich das mehr oder weniger direkt über player::play() machen. und nicht die maus dort positionieren, wo sich das entsprechende button befindet.Das sind halt Erfahrungen, die man sammelt. Meistens ist die Sache einfacher und logischer als man denkt.
Ich habe den eindruck, dass du denks, dass ich noch neu in der programmierung bin. aber ich programmiere schon seit 8 jahren c++.
obwohl..., das muss nichts aussagen.

-
Wenn meine Fensterklasse funktionen bietet um über GuiBasisElement* zu itererieren. Was ist daran auszusetzten dass ich so auf den Player dann auch zugreife?
Warum soll das Fenster (bitte darüber nachdenken!) die Play-Methode aufrufen wollen? WAS hat das Fenster mit dem Play zutun? Das Fenster kennt nur das GuiBasisElement-Interface.
Noch zusätzlich irgenwelche Zeiger zu speichern ist rendundant und kann Fehler verursachen. (Mein Player wird ohne meine Kenntnis durch einen anderen ersetzt.)
Nein, ebend nicht! Denn dein Pointer ist private! (man soll es nicht glauben) Meinetwegen machste halt keinen Pointer:
class Anwendung { MeinAppleQuickTimePlayer player; // kein Pointer Fenster fenster; public: Anwendung() { fenster.add(&player); // allgemein } };Das mit der Redundanz ist kein Argument. Wir reden hier über OO-DESIGN und nicht über "Wie spare ich 4 Byte?".
Aber wenn ich meinen Player übers Netzwerk steuern will. will ich das mehr oder weniger direkt über player::play() machen. und nicht die maus dort positionieren, wo sich das entsprechende button befindet.
Auch dann kennt dein Netzwerk-CLient ein bestimmtes Interface. (selbst wenn es nur ein bestimmter String-Schlüssel ist) Es kann ein Wrapper sein, der am anderen Ende der Leitung wieder die play-Methode kennt. (z.B. durch erkennung des String-Schlüssels)
Ich stelle fest, das du immer wieder andere Ausnahme-Szenarios vorbringst, sobald ich dir eine Nicht-Cast-Lösung aufzeige. Komisch, oder?
Deine 8 Jahre sind schön und gut. Aber 1. lernt man nie aus. Und 2. sind gerade alte C++-Programmierer nicht DIE C++-Profis. Wenn ich sehe, das Projekte immer noch auf VC6 rumgurken und NICHT auf VC8 umsteigen können, weil sie nicht sauber C++ programmiert haben, sagt mir das sehr viel.
Ich kenne dich überhaupt nicht, deshalb ist mein vorheriger Absatz allgemein gesprochen. Und das du C++-Neuling bist, muß ich davon ausgehen, da du nicht registriert bist, und somit keine Infos über dich habe.
-
Artchi schrieb:
Warum soll das Fenster (bitte darüber nachdenken!) die Play-Methode aufrufen wollen? WAS hat das Fenster mit dem Play zutun? Das Fenster kennt nur das GuiBasisElement-Interface.
Ich habe nie behauptet, dass ich auf die Play-Methode innerhalb der Fenster-Klasse zugreiffe. Das Fenster bietet Methoden um über die Elemente zu iterieren.
Noch zusätzlich irgenwelche Zeiger zu speichern ist rendundant und kann Fehler verursachen. (Mein Player wird ohne meine Kenntnis durch einen anderen ersetzt.)
Nein, ebend nicht! Denn dein Pointer ist private! (man soll es nicht glauben) Meinetwegen machste halt keinen Pointer:
class Anwendung { MeinAppleQuickTimePlayer player; // kein Pointer };Das mit der Redundanz ist kein Argument. Wir reden hier über OO-DESIGN und nicht über "Wie spare ich 4 Byte?".
Bei Redundanz geht es mir nicht so sehr 4 bytes einzusparen, sondern um den zusätzlichen Aufwand um Sicherzustellen, dass der zeiger IMMER auf ein gültiges Objekt verweist.
Auch dann kennt dein Netzwerk-CLient ein bestimmtes Interface. (selbst wenn es nur ein bestimmter String-Schlüssel ist) Es kann ein Wrapper sein, der am anderen Ende der Leitung wieder die play-Methode kennt. (z.B. durch erkennung des String-Schlüssels)
Gegen Schlüssel jeglicher Art bin ich ziemlich alergisch. Sie erfordern abwärtskompatibilität. Vor allem, wenn man Komponenten von 3. herstellern verwendet. Ich will aber nicht abwärtskompatibel sein. Will auch jederzeit die schlüssel ändern können, wenn ich lustig danach bin.
Ich stelle fest, das du immer wieder andere Ausnahme-Szenarios vorbringst, sobald ich dir eine Nicht-Cast-Lösung aufzeige. Komisch, oder?
Ich muss ja meine Argumentation.... verteitigen.
Ich versuche halt so zu programmieren, dass selbst die abwegigsten Ausnahme-Szenarien umgesetzt werden können.