Grundlegende Fragen über das Design einer Shared Library in C++ mit Java im Hinterkopf



  • Also in etwa so?

    struct project {...};
    struct entry {...};
    
    class platform
    {
    public:
      add_or_change_entry(size_t index, entry e);
      add_or_change_project(size_t index, project p);
    
    private:
      container projects_;
      container entrys_;
    };
    

    Was spricht dagegen, dass genau so zu machen?
    Edit: Mit entry in project, hatte das überlesen.



  • Genau, etwas in der Art. Nun möchte ich aber die Implementierung von der Schnittstelle abtrennen, um zum Beispiel beim Hinzufügen/Änderung von privaten Attributen in der Implementierung nicht gleich das ganze Offset zu verschieben (Bin auf dem Gebiet neu & daran mich einzulesen).

    Nun war meine Idee:
    - Öffentliche Klasse besitzt einen Pointer zu der libraryinternen Implementierung
    - Methodenzugriffe auf die öffentliche Klasse werden an die Implementierung weitergeleitet, diese arbeitet die Sache ab
    - Änderungen in der Implementuerung machen eine Neukompilierung der Applikation mit der (neuen) Library überflüssig ?

    Oder habe ich da was falsch verstanden ? An dieser Stelle könnte ich doch das PIMPL Pinzip verwenden ?

    Gruss Simon



  • swaechter schrieb:

    Nun möchte ich aber die Implementierung von der Schnittstelle abtrennen, um zum Beispiel beim Hinzufügen/Änderung von privaten Attributen in der Implementierung nicht gleich das ganze Offset zu verschieben (Bin auf dem Gebiet neu & daran mich einzulesen).

    Wozu? Wo liegt das Problem, wenn sich das Layout der Membervariablen ändert?

    Was du beschreibst, ist gerade das PImpl-Idiom. Wie erwähnt wird es primär zur Verringerung von Compilezeit-Abhängigkeiten eingesetzt.



  • Nexus schrieb:

    Wozu? Wo liegt das Problem, wenn sich das Layout der Membervariablen ändert?

    Klar könnte ich darauf verzichten und immer davon ausgehen, dass Applikation und Library neu kompiliert & gelinkt werden, aber eventuell möchte ich das eines Tages ändern und dann alles umbauen, nur um das zu erreichen ? Lieber fange ich dann gleich richtig an und setze auf eine lose Kopplung zwischen Implementierung und Schnittstelle

    Betreffend Businessobjekten: Gibt es da auch eine gute Möglichkeit, eine lose Kopplung zu erreichen oder schreibt man einfach eine Klasse, bestehend aus lauter virtuellen Funktionen und das eigentliche (interne) Businessobjekt erbt davon ? PIMPL würde in einem solchen Fall ja einen enormen Overhead generieren (Was mehr auffällt als bei einer Klasse, die aus lauter Logik besteht und Inpputchecking betreibt) ?



  • swaechter schrieb:

    Klar könnte ich darauf verzichten und immer davon ausgehen, dass Applikation und Library neu kompiliert & gelinkt werden, aber eventuell möchte ich das eines Tages ändern und dann alles umbauen, nur um das zu erreichen ? Lieber fange ich dann gleich richtig an und setze auf eine lose Kopplung zwischen Implementierung und Schnittstelle

    Nachträglich pimpl einfügen? Das ist quasi umsonst, da muss ja nicht einmal die Schnittstelle geändert werden.

    PIMPL würde in einem solchen Fall ja einen enormen Overhead generieren

    lol



  • justlol schrieb:

    swaechter schrieb:

    Klar könnte ich darauf verzichten und immer davon ausgehen, dass Applikation und Library neu kompiliert & gelinkt werden, aber eventuell möchte ich das eines Tages ändern und dann alles umbauen, nur um das zu erreichen ? Lieber fange ich dann gleich richtig an und setze auf eine lose Kopplung zwischen Implementierung und Schnittstelle

    Nachträglich pimpl einfügen? Das ist quasi umsonst, da muss ja nicht einmal die Schnittstelle geändert werden.

    PIMPL würde in einem solchen Fall ja einen enormen Overhead generieren

    lol

    Danke für deinen sehr konstruktiven Beitrag. Wenn Du schon solchen Content schreibst, registrier dich doch bitte, dass man dich erkennen kann (und ich dir konkret aus dem Weg gehen kann)

    Betreffend PIMPL nachträglich einfügen:

    1.) Was muss nicht mehr eingefügt werden ? Sollte es wie in Frage 2 sein hast Du definitiv kein PIMPL...
    2.) Nein sicher nicht. Hast Du eine Klasse, in welcher gewisse Methoden exportiert und andere nicht exportiert werden, verschiebt sich dein Offset immer, wenn Du gewisse Bestandteile änderst (Methoden/Attribute etc). Das ist nicht gerade das, was ich anstrebe (Betreffend loser Kopplung).

    Vorherige Frage steht immer noch im Raum



  • Binärschnittstellen in C++ sind sowieso eine Angelegenheit für sich. Du bist wegen fehlendem standardisierten ABI relativ eingeschränkt und oft zum Neukompilieren gezwungen (spätestens wenn du den Compiler oder nur schon die Version oder bestimmte Flags wechselst).

    Du solltest dir also überlegen, wie weit du deswegen dein Design verkomplizieren willst.



  • Hallo Nexus

    Danke für deinen Antwort. Ich muss ein paar Sachen klarstellen und ergänzen, da ich erst seit gestern in das Thema reingekommen bin und sich der Thread doch recht entwickelt hat. Früher habe ich Libraries einfach exportiert und das wars - mehr nicht (Schnittstelle und Implementierung = Eine Klasse). Seit gestern habe ich mich vertieft damit auseinandergesetzt, um das ganze sauberer gestalten zu können. Zu ergänzen (meinerseits) ist:

    Infrastruktur
    - Ich verwende für die Applikation und die Library denselben Compiler und dasselbe CRT (Sprich MSVC und dessen CRT oder GCC/Clang und dessen GLIBC)
    - Es kann vorkommen, dass die Applikation wegen Änderungen in der Library nicht neukompiliert wird (Wir reden über eine Patch Level Änderung in der Library, nicht Major & Minor, deshalb muss gewährleistet sein, dass sich das Offset nicht ändert (Z.B neue Variable wird eingeführt). ANMERKUNG: Ich habe mich noch nicht vertieft in Offset Changing eingelesen. Wird das ganze über eine lose Kopplung realisiert, funktioniert die Applikation auch mit der geupdateter Library. Verwende ich aber 1 Klasse wie bereits mehrmals in diesem Thread vorgeschlagen wurde, ist es (gut) möglich, dass sich das Offset der Library ändert [und das der Applikation nicht, da kein recompile].Das CRT zwischen Applikation und Library bleibt aber auch in diesem Fall gleich (Build Server)

    Betreffend deiner Aussage 1:
    - Wird deine Aussage nicht eher unwichtig/rückt in den Hintergrund, wenn ich garantieren kann, dass ich denselben Compiler und dasselbe CRT verwenden kann. Es erfolgt definitv kein Compiler/CRT Mixing ! Entweder kompiliert das Buildsystem ALLES oder nur Änderungen, aber immer mit dem gleichen Compiler/CRT.

    Betreffend deiner Aussage 2:

    Nexus schrieb:

    Du solltest dir also überlegen, wie weit du deswegen dein Design verkomplizieren willst.

    Wie darf man das verstehen. Könntest Du mir ein komplettes Codebeispiel geben, wie Du es machen würdest, wenn dir jemand den Auftrag gibt, eine Klasse zu schreiben, welche Projekte und Eintrage machen/editieren/löschen kann, WENN Du davon ausgehen kannst, dass der Compiler und das CRT IMMER dasselbe sind und eine lose Kopplung von Nöten ist ? Ich wär dir dafür sehr dankbar.

    Schöne Weihnachten dir & Mitleser
    Gruss Simon



  • Bezüglich ABI kompatiblen Änderungen in Klassen:

    AFAIK ändert sich die ABI Schnittstelle einer Klasse nicht, wenn ein neuer Member(eine neue Memeber-Methode?) immer ans ende der Klassen definition gepackt wird.

    Wobei ich nicht weis, ob sich die ABI eventuell ändert, wenn eine Änderung in einer Klasse gemacht wird, welche als Basis für andere Klassen Verwendung findet



  • firefly schrieb:

    Bezüglich ABI kompatiblen Änderungen in Klassen:

    AFAIK ändert sich die ABI Schnittstelle einer Klasse nicht, wenn ein neuer Member(eine neue Memeber-Methode?) immer ans ende der Klassen definition gepackt wird.

    Bei nicht-statischen Datenmembern wird die Klasse dadurch bei allen Systemen die ich kenne inkompatibel, da sich sizeof(T) ändert.

    Neue Methoden sind dagegen meist egal. So lange sie nicht virtuell sind, ist dabei auch egal wo man sie dazuschreibt. Und wenn sie virtuell sind, man sie aber brav hinter alle anderen virtuellen Funktionen schreibt, dann ist es auch egal. Zumindest eben auf den Systemen nicht ich kenne.

    Hat aber mit Standard C++ nix zu tun, da der Standard diesbezüglich nix vorschreibt.

    Wobei ich nicht weis, ob sich die ABI eventuell ändert, wenn eine Änderung in einer Klasse gemacht wird, welche als Basis für andere Klassen Verwendung findet

    Wenn nicht-statische Datenmenber betroffen sind, ist die Chance gross, dass alle abgeleiteten Klassen neu übersetzt werden müssen. Wenn sich die Grösse oder das Layout der Klasse bzw. abgeleiteten Klassen dadurch ändert auch der gesamte Client Code.

    Sowas sind aber Dinge über die ich mir üblicherweise nicht den Kopf zerbreche.
    Für mich gibt es ein paar sinnvolle Varianten damit umzugehen:
    * Reines C Interface
    * COM
    * PIMPL
    * volles C++ Interface + immer alles neu Übersetzen

    Zwischenlösungen mache ich da nur wenn ich wirklich muss. Was in den letzten Jahren nicht vorgekommen ist. Ich hab' aber auch nur mehr ein Projekt wo ich ein stabiles binary Inteface garantieren muss, und das verwendet COM.


Anmelden zum Antworten