Proxys und const-correctness



  • Ich habe erläutert, dass ich dynamische Polymorphie brauche, weil sich in manchen Programmteilen zur Laufzeit entscheidet, ob dort ein Proxy auf ein Objekt oder das eigentliche Objekt übergeben wird - was willst Du denn noch? 🙂

    Zum Edit: Wie gesagt, es gibt nicht die perfekte Lösung. Wenn die Lösung, die sonst überall passt und die meisten Vorteile zu ergeben scheint, ein Alarmsignal feuert, ist das eben so, solange es nur ein Signal ist. Ohne das durchzudenken, reicht mir das nicht als Gegenargument, solange nicht eine bessere Lösung präsentiert wird...

    Ist wie gesagt ein Abwägen von Vor- und Nachteilen. Ich teile nicht die Auffassung, dass irgendwo ein theoretisches Argument (Konsistenz, const-cast signalisiert schlechtes Design, Interfaces sind java-like und haben in C++ nichts zu suchen) so stark wiegt, dass es die praktischen Vorteile überkompensiert.

    Ich gehe jetzt erstmal schlafen, gute Nacht 🙂



  • Ich habe erläutert, dass ich dynamische Polymorphie brauche, weil sich in manchen Programmteilen zur Laufzeit entscheidet, ob dort ein Proxy auf ein Objekt oder das eigentliche Objekt übergeben wird - was willst Du denn noch?

    Das verstehe ich schon. Leider kannst du ConstProxy mit der Loesung von facepalm nicht als Ersatz fuer Proxy oder das eigentliche Objekt benutzen, weil ConstProxy nicht Teil der Vererbungshierarchie (is_a Beziehung) ist.

    weil halbgare oder Totschlagargumente auf den Tisch geworfen werden...

    Die Argumentation mit is_a ist nicht halbgar.

    Zur Erklaerung: Ich habe C++-Programmierstil mit Java-Programmierstil anhand deines Interface/Proxy/ConstProxy-Beispiels. Voellig emotionslos. Ich habe auch diesen Thread angefuehrt, warum GoF-Patterns nicht immer die beste Wahl fuer C++ sind: http://www.c-plusplus.net/forum/319393-20 . Das hat aber nichts mit dir zu tun.



  • Sone schrieb:

    Ergo, nehme niemals die Adresse von const& Variablen.

    Man sollte einfach nie davon ausgehen, dass eine const-Referenz langlebig ist. Und das führt hier dazu, dass der komplette Code so nicht funktioniert, sondern man einen Zeiger nehmen muss - sowohl für die interne Referenzierung als auch für die gesamte Schnittstelle (um Inkonsistenz zu vermeiden).

    Naja...
    Ich kann mir jetzt nicht vorstellen wie man sich damit in genau dieser Situation ins Knie schiessen kann.

    Das Interface wird wohl kaum eine konkrete Klasse mit einem conversion-ctor sein, und das konkrete Objekt vermutlich nicht kopierbar sein.
    Gut, movebar wäre noch drinnen.

    Ganz Allgemein geb ich dir aber Recht: wieso sich auf nicht sehr sichere Annahmen darüber verlassen wie die Interface-Klasse und die konkrete Klasse eventuell aussehen, wenn man mit nem Zeiger viel besser kommunizieren kann was abgeht.



  • vielleicht solltest du das nächstes mal die Funktionen nicht virtuell machen.

    Aber dann hast du ja gegen die Rahmenbedingungen verstoßen, habe ich gar nicht bemerkt. Wenn du die Methoden nicht virtuell hast, dann ist doch klar, dass der von mir zitierte Paragraph gültig wird und Methoden die nicht benutzt werden auch nicht instantiiert werden.

    Dann ist die Lösung aber auch wieder falsch.



  • Sone schrieb:

    Dann ist die Lösung aber auch wieder falsch.

    hast ja recht *wuschelwuschel*



  • knivil:

    Ich habe C++-Programmierstil mit Java-Programmierstil anhand deines Interface/Proxy/ConstProxy-Beispiels. Voellig emotionslos.

    Moment, meinst Du, Du hältst meinen Code für C++- mit Java-Stil gemischt (oder auch nur letzteres) oder dass Du es selbst so nutzt? Ich gehe Mal vom ersteren aus.

    Und dann ist das eben für diesen Teil ein Stil, den man auch in Java so nutzen würde. Aber das heißt ja nicht gleichzeitig, dass es schlecht ist oder der Code dadurch dequalifiziert wird. Es gibt in meinen Augen an der Stelle keine bessere Lösung für meine Praxis. Und dass GoF-Patterns nicht immer optimal für C++ sind, ist doch ein alter Hut. Nicht immer impliziert aber eben "manchmal eben doch".

    Zudem werden Proxys in C++ ja durchaus eingesetzt. Das Einzige, was hier stört, ist ja, dass ich noch ein Interface drüberpappe. Dann müsste man ja sagen, dass dynamische Polymorphie java-like ist? Oder Interfaces? Also basierend auf den Aussagen hier komme ich zu keiner konsistenten Definition von "java-like", die ich halt bräuchte, wenn das so schlimm wäre, dass man es auf gar keinen Fall in C++-Code einsetzen darf (wirkt für mich so, als wäre das hier ständig gefordert, vielleicht vertue ich mich da).

    Ok, aber zum Thema: Wer ein const Interface* erwartet, kann den ConstProxy erhalten, dafür ist der const Interface* operator() doch da. Somit verhält sich ConstProxy wie ein Erbe von Interface. Daher wird is_a quasi simuliert. Besser gesagt, wird "ConstProxy is a const Interface" simuliert (na ja, jedenfalls für Referenz- und Zeigerparameter). Geschieht nur nicht klassisch erstklassig durch Vererbung. Aber Vererbung würde ja auch sagen "ConstProxy is an Interface" und das ist ja keine korrekte Aussage. Eigentlich bräuchte man so was wie " : public const Interface" oder irgendwo anders einen Qualifizierer, aber da C++ das nicht anbietet (hätte ja auch wieder Probleme), muss man es anders tun und facepalms Lösung scheint das so weit doch zu tun.



  • Hi,

    nach wie vor an einer Antwort interessiert. 🙂

    Mir ist jetzt jedoch auch aufgefallen, dass das Interface mir nichts bringt *schäm*. Warum?

    Weil ich an der Stelle, wo Proxy ODER eigentliches Objekt übergeben werden, ein logischer Konflikt vorliegt. Denn wie soll man bitte gestalten, dass man entweder Proxy oder eigentliches Objekt erhält? Ein Proxy ist ja kopierbar, er verweist ja nur auf das Objekt bzw. leitet alles weiter. Die Range selbst aber nicht. Wenn ich also ein Interface* habe, muss ich höllisch aufpassen, da dort auf keinen Fall ein Zeiger auf einen Proxy reinkommen darf, weil man den Proxy ja ständig by value übergibt, da die Kopie günstig und erwünscht ist.

    Jetzt habe ich dämlicherweise gemerkt, dass es echt schnell passieren kann, dass man eben so einen Zeiger übergibt. 👎 Insofern schmeiß ich das Interface jetzt in der Tat weg...

    Designproblem bleibt jedoch der Falll, dass man entweder Proxy oder Referenz auf Objekt (ohne Proxy-Indirektion) übergeben kann... Das habe ich jetzt über die Indirektion gelöst, dass es eine Struktur Occurence gibt, die sowohl Zeiger auf ActualObject als auch ein Objekt (ohne Zeiger natürlich) des Proxys hat. Wenn der Zeiger nullptr ist, bedient man sich als Anwender dann dem Proxy...

    Echt unschön, hat jemand eine Idee, wie ich das besser löse? Man könnte einen Proxy machen, der einfach alles weiterleitet, diesen und den eigentlichen Proxy von einer gemeinsamen Basis ableiten lassen und dann gezwungen werden immer einen der beiden Proxys (wovon der eine ja quasi nur Zeiger ist) zu übergeben... aber das ist doch auch eklig und ich muss wieder Polymorphie nutzen 😞



  • Eisflamme schrieb:

    Ein Proxy ist ja kopierbar, er verweist ja nur auf das Objekt bzw. leitet alles weiter.

    Das passiert, wenn man sich nicht an meine Hinweise hält.

    Der Fehler:

    Man muss jedoch auch noch operator const Interface* überladen, nicht jeder mag Referenzen. Aber sonst scheint das okay zu sein.

    Proxy = Interface = Noncopyable = zeigt immer aufs gleiche Objekt = Referenz

    Du kannst von mir aus den operator& überladen, damit er ein const Interface* zurückgibt. Aber Proxy=Interface, nicht Proxy=Interface*

    Ich finde es aber toll, dass du es auch ohne Vererbung gelöst hast. Das ist nämlich weitaus die bessere Variante.



  • Na ja, es waren viele Hinweise und ich hatte ja auch einige Fragen dazu, wie ich es dann anwenden soll, weil ich es nicht ganz verstand. 🙂

    Aber ich glaube, wir haben hier auch eine andere Vorstellung vom Proxy an sich. Jedenfalls brauche ich den Proxy (oder wie man ihn dann gerne nennen würde) bei mir für einen Zugriff auf ein bereits bestehendes Objekt, das sich eben in einem Baum befindet. Ein sich in einem Baum befindliches Klassenobjekt hat bei mir Verhaltensunterschiede zu einer solchen Klasse, die nicht in einem Baum abgelegt ist.

    Daher will ich eben so ein Proxy-Objekt nutzen, über das man das im Baum befindliche Objekt unter Berücksichtigung der Phänomene - da besagtes Objekt im Baum ist - ändern kann. Die Klasse des eigentlichen Objekts soll aber unberührt bleiben, weil man die eben auch außerhalb vom Baum nutzen kann.

    Daher fand ich so einen "Proxy"-Ansatz ganz chic, die eigentliche Klasse bleibt unberührt und für andere Kontexte nutzbar, sobald die Elemente im Baum vorkommen, nutzt man aber den Proxy für den Zugriff.

    Nur ist der Proxy dann eben Referenz auf ein bestehendes Objekt. Wie würdest Du das denn lösen?



  • So isch des eben beim Software entwickeln. Es ist und bleibt ein Prozess 🙂 Ständig dran arbeiten und verbessern. Zum Schluss wirst du aber mit etwas schickem belohnt werden und zufrieden sein.



  • Ja, ist wirklich ein Prozess, ich habe nur das Gefühl, dass ich nicht wirklich weit bin und ich werde mich auch nicht jahrzehntelang damit befassen können. 😞 Zudem glaube ich, dass - angenommen, es gäbe einen Schluss - ich immer hier ins Forum kommen würde, den Code posten würde und er zerrissen würde. Dann wäre ich aber nicht wirklich zufrieden. Von daher finde ich, dass Deine Aussage "Zum Schluss bist Du zufrieden" nicht so stimmt. 😃

    Aber na ja, mein Design jetzt ist schon deutlich besser als vorher. Und wenn man sich so ansieht, was für kommerzielle Softwareprojekte mit schlimmen Code rumschwirren, darf man doch eigentlich schon sehr zufrieden sein, wenn man die selbst gesetzten Ziele bzgl. Änderbarkeit und Erweiterbarkeit gut hinbekommt, oder?

    Die Frage bzgl. der Übergabe solcher nicht-erbenden Proxy-Klassen an jemand anderen habe ich Mal verlagert: http://www.c-plusplus.net/forum/319547


Anmelden zum Antworten