Implementierung von bidirektionalen Ports



  • Hallo,
    ich versuche mich etwas an UML und hab gelernt, dass Verbindungen zwischen Ports über Referenzen beim Konstruktor hergestellt werden. Also verwendet Klasse A das Interface I, welches Klasse B zur Verfügung stellt, würde ich das so machen:

    class I {};
    
    class A {
      I& myI;
    
      A(I& i) : myI(i) {};
    };
    
    class B : public I {};
    
    int main() {
      B myB;
      A myA(myB);
    }
    

    Was aber, wenn zwischen A und B eine bidirektionale Verbindung besteht, also B auch ein Interface hat, was von A bedient wird. Wenn ich B instanziiere, gibt es ja A noch nicht. Gehe ich dann auf Pointer und setze die Verbindung nachträglich?

    Gruß,
    Heimchen



  • Der Sinn von model-driven development ist ja, dass man zuerst mal das Design erstellt, dann den Code.

    Wie sieht denn das UML-Diagramm dazu aus?


  • Mod

    Im Übrigen sind Referenzen als Member i.d.R. keine gute Idee; Zeiger sind vorzuziehen.



  • minastaros schrieb:

    Der Sinn von model-driven development ist ja, dass man zuerst mal das Design erstellt, dann den Code.

    Das Modell ist fertig, jetzt muss es möglichst originalgetreu in Code überführt werden.

    minastaros schrieb:

    Wie sieht denn das UML-Diagramm dazu aus?

    Das Diagramm zu dem Code enthält die beiden Klassen a und B und das Interface I. Von A nach I besteht eine Dependency, von B nach I besteht eine Realize Beziehung.
    Alternativ könnte man an A auch ein Required Interface vom Typ I malen und an B das Gegenstück.
    Bei dem, wozu ich den entsprechenden Code suche, kommt ein zweites Interface hinzu, welches eine Dependency von B hat und ein Realize von A.

    Arcoth schrieb:

    Im Übrigen sind Referenzen als Member i.d.R. keine gute Idee; Zeiger sind vorzuziehen.

    Bisher habe ich nur die Umsetzung mit der Referenz zu den Interfaces gefunden (z.B. hier: http://www.cppbuch.de/uml.pdf). Zeiger werden dagegen eher für Assoiciations oder Aggregations benutzt. Macht für mich auch Sinn, schließlich muss das Interface angebunden sein (sonst wär es ein Port), während eine Association oder Aggregation ja eher lose ist - also auch NULL sein kann. Immer in C++ natürlich. Nur muss ich den Anbieter eines Interfaces dann eben schon haben, wenn ich den Nutzer Anlege...


  • Mod

    heimchen schrieb:

    Arcoth schrieb:

    Im Übrigen sind Referenzen als Member i.d.R. keine gute Idee; Zeiger sind vorzuziehen.

    Bisher habe ich nur die Umsetzung mit der Referenz zu den Interfaces gefunden (z.B. hier: http://www.cppbuch.de/uml.pdf). Zeiger werden dagegen eher für Assoiciations oder Aggregations benutzt.

    Es ist egal in welchem Kontext die Referenz als Member auftaucht; Ein konstanter Zeiger ist vorzuziehen.



  • Arcoth schrieb:

    Es ist egal in welchem Kontext die Referenz als Member auftaucht; Ein konstanter Zeiger ist vorzuziehen.

    Warum? Wenn ich eine Referenz/Pointer auf z.B. einen std::ostream in meiner Klasse speichern möchte (ich setze mal voraus, dass das zugehörige Objekt mindestens so lange lebt wie das Objekt meiner Klasse), dann nehme ich auf jeden Fall die Referenz weil Operatorüberladung dann vernünftig funktioniert. Ich sehe keinerlei Vorteile bei der Verwendung von Pointern, wenn man kein rebind braucht.


  • Mod

    sebi707 schrieb:

    dann nehme ich auf jeden Fall die Referenz weil Operatorüberladung dann vernünftig funktioniert.

    Was hat Operatorenüberladung damit zu tun? Der Member wird doch privat sein, demnach die Syntax unwichtig.

    Ich sehe keinerlei Vorteile bei der Verwendung von Pointern, wenn man kein rebind braucht.

    Kein Standardlayout. Keine pointer-to-member.
    Erzeugt z.Z. in einigen Situationen undefiniertes Verhalten (siehe CWG 1404). Dies trifft auch auf konstante Member zu, daher sollte der Zeiger natürlich nicht const sein, mea culpa.



  • Arcoth schrieb:

    Was hat Operatorenüberladung damit zu tun? Der Member wird doch privat sein, demnach die Syntax unwichtig.

    Nur weils private ist muss ich ja nicht die umständliche Syntax nutzen.

    Kein Standardlayout. Keine pointer-to-member.
    Erzeugt z.Z. in einigen Situationen undefiniertes Verhalten (siehe CWG 1404). Dies trifft auch auf konstante Member zu, daher sollte der Zeiger natürlich nicht const sein, mea culpa.

    OK Referenzen haben auch Nachteile. Hier gibts eine umfangreichere Diskussion.



  • Wenn Zeiger so viel sinnvoller sind, Frage ich mich, warum ich für diesen Fall ausschließlich Referenzen zur Implementierung gefunden hab. Auch sonst werden Referenzen in der Literatur bevorzug (als Parameter o.ä.). Dann müssten sich ja alle anderen täuschen...


  • Mod

    sebi707 schrieb:

    Arcoth schrieb:

    Was hat Operatorenüberladung damit zu tun? Der Member wird doch privat sein, demnach die Syntax unwichtig.

    Nur weils private ist muss ich ja nicht die umständliche Syntax nutzen.

    Wegen einer syntaktischen Petitesse willst du ggf. semantische Nachteile eingehen?

    Auch sonst werden Referenzen in der Literatur bevorzug (als Parameter o.ä.).

    Natürlich, als Parameter sind Referenzen hauptsächlich konzipiert.



  • Arcoth schrieb:

    Kein Standardlayout. Keine pointer-to-member.

    Das ist doch eh nicht gegeben:

    Arcoth schrieb:

    Der Member wird doch privat sein, demnach die Syntax unwichtig.

    wenn der Member privat ist (müssen doch schließlich alle den gleichen access haben)? Und pointer-to-member geht ja auch nicht wenn das Member privat ist.

    Arcoth schrieb:

    Erzeugt z.Z. in einigen Situationen undefiniertes Verhalten (siehe CWG 1404).

    Das ist aber ein Bug der sowieso nur für Unions gilt, wenn ich das richtig verstehe (also hier auch nicht relevant)?

    Würde mich interessieren, weil ich benutze auch ab und zu Referenzen als Member und finde das in einigen Fällen von der Modelierung her passender als Pointer.


  • Mod

    Das ist aber ein Bug der sowieso nur für Unions gilt,

    Ja, aber er zeigt die Problematik auf, die sich hinter Referenzmembern verbirgt: Sie sind keine Objekte, müssen aber in einem "dargestellt" werden. Für mich scheint das einfach ein völlig falscher Anwendungsfall von Referenzen zu sein.

    <Sone>Leider musste ich feststellen, dass ich ich meine Meinung dazu nur unzureichend mit technischen Argumenten belegen kann. 😞 </Sone>

    Würde mich interessieren, weil ich benutze auch ab und zu Referenzen als Member und finde das in einigen Fällen von der Modelierung her passender als Pointer.

    Naja, wenn dir die Semantik der generierten Konstruktoren passt, usw. - i.e. wenn dir die Nuancen bewusst sind - dann ist das selbstverständlich in Ordnung. Meine Tirade war eine Mischung aus Quod licet Iovi und meinem Bauchgefühl (s.o.).

    happystudent schrieb:

    Arcoth schrieb:

    Kein Standardlayout. Keine pointer-to-member.

    Das ist doch eh nicht gegeben:

    Ich bezog mich auf allgemeine Fälle. In diesem Fall greifen die wahrscheinlich beide nicht.

    Und pointer-to-member geht ja auch nicht wenn das Member privat ist.

    Warum nicht? Oder worauf beziehst du dich?



  • Arcoth schrieb:

    Und pointer-to-member geht ja auch nicht wenn das Member privat ist.

    Warum nicht? Oder worauf beziehst du dich?

    Naja, es kann gut sein das ich grade auf dem Schlauch stehe. 😃 Aber:

    #include <iostream>
    
    class A { int x = 42; };
    
    int main() 
    {
        int A::*ptrX = &A::x; // Error: 'int A::x' is private
        std::cout << A().*ptrX << '\n';
    }
    

    geht halt nicht wenn x private ist wie von dir vorgeschlagen und dann ist es auch egal ob Pointer oder Referenz weil man ja eh keinen Zugriff auf x hat?


  • Mod

    Ja, aber was wenn der Memberzeiger intern erzeugt wird?



  • Arcoth schrieb:

    Ja, aber was wenn der Memberzeiger intern erzeugt wird?

    Ok, das würde dann nicht gehen. Aber die Frage wäre wofür man sowas brauchen soll?

    Wenn ich eine Memberfunktion anbiete die mir einen Data-Memberpointer zurückgibt, dann ist dieser Datapointer ja eh schon mit der Instanz "verknüpft" (weil man ohne selbige ja nicht an den Pointer rankommen würde), also kann man eigentlich auch gleich einen normalen Pointer zurückgeben.

    Gut, wenn man eine static Memberfunktion hat die einen solchen Memberzeiger zurückgeben soll, dann würde es nicht gehen... Aber wie oft und warum sollte man sowas brauchen (kann sein dass man das braucht, ist mir aber noch nie passiert)?


  • Mod

    Man braucht es fast nie. War auch ein sehr fadenscheiniges Argument.


Log in to reply