Problem mit Software Architektur (C++)



  • @SeppJ

    Es ist halt ein bisschen komisch, da eine Klasse die nur pure virtual Funktionen hat, keinerlei Funktionalität hat.

    Das ist ja genau der Sinn 🙂

    Stell die folgende Situation vor:
    Du hast ein fertiges Projekt. Nun kommt der Chef oder der Kunde und sagt, wir müssen nun noch ein umfangreiches Logging System einfügen, der Zustand von einigen Objekten muss nun geloggt werden können. "LORD, wie soll denn dass gehen, davon hat beim Design der Architektur niemand was gesagt!"

    Kein Problem:

    class ILoggable{
    public:
     virtual string *LogStatus() = 0;
    };
    
    Logger{
    public:
     void RegisterLoggable(ILoggable *Loggable);
    };
    

    Nun kann man jedes objekt in der ganzen Applikation Loggable machen, indem es einfach das Loggable interface implementiert, oder in C++ virtuell erbt.
    Der Logger kann nun den Status von jedem Objekt in seiner Applikation zu jedem Zeitpunkt loggen ohne diese Objekte in irgendeiner Weise kennen zu müssen, ist das nicht Toll? 😃



  • Weiterer Vorschlag und auch passend zu Dravere's NVI Anmerkung:
    Hier sieht z.B. IsLoaded() nicht unbedingt danach aus, dass die pure virtual sein muss.
    Gegenvorschlag:

    class IResource{
    public:
       void Load();
       bool IsLoaded();
    private:
      bool loaded;
      void virtual doLoad();  // Wobei void bei Load komisch ist, regelst du das über Exceptions, wenn's nicht klappt?
    };
    ...
    void IResource::Load()
    {
      doLoad();
      loaded = true;  // what ever, bzw. besser je nach Rückgabewert setzen
    }
    bool IResource::IsLoaded()
    {
      return loaded; // what ever
    }
    


  • @Dravere
    Da hast du zu 100% recht, daher schreibe ich auch immer eine Default Teilimplementierung, bspw. AbstractResource, welche genau diese Aufgaben übernimmt. Für jede Resource kann man schliesslich selbst entscheiden, ob man von der AbstractResource Klasse erben will, welche einen Grossteil der "in den meisten Fällen identisch implementierten Teile" bereits erledigt, oder ob es bessär ist, eine komplett neue Implementation zu schreiben.



  • Ishildur schrieb:

    Nun kann man jedes objekt in der ganzen Applikation Loggable machen, indem es einfach das Loggable interface implementiert, oder in C++ virtuell erbt.

    Irgendwie hab ich das Gefühl, du hast nicht verstanden, wozu virtual Vererbung in C++ da ist.



  • @Jockelx
    Es gibt vielleicht Resourcen, bei denen das nicht ganz so einfach ist. Einige haben vielleicht Dependencies, dann müsste IsLoaded auch noch prüfen, ob diese alle auch geladen sind. Vielleicht ist eine Resource auch nur ein Container für andere Resourcen, welche geladen sein müssen, dann wäre das bool für die Katz. Eine andere Resource muss vielleicht zusätzlich eine Netzverbindung prüfen usw. Es gibt unzähliche Möglichkeiten und nicht immer kann das in einem simplen bool nachgesehen werden.



  • Irgendwie hab ich das Gefühl, du hast nicht verstanden, wozu virtual Vererbung in C++ da ist.

    Wie gesagt ich masse mir nicht an alles zu wissen und zu verstehen, ich lerne gerne dazu 🙂
    Es gibt natürlich probleme, wenn nun zwei Interfaces eine Methode mit demselben Namen sowie derselben Signatur anbieten. Bsp:

    class Loggable{
     public: virtual string *GetName() = 0;
    }
    
    class Scriptable{
     public: virtual string *GetName() = 0;
    }
    
    class MyObject:virtual public Loggable,virtual public Scriptable{
     public: string *GetName();
    }
    

    Ich denke, dafür is virtuelle Verwebung da, damit die Methode GetName nicht doppeldeutig ist. Ich will ja nicht, dass MyObjekt dem Logger und dem Skriper zwei unterschiedliche Namen zurückgibt.



  • Mmh, finde ich aber auch nicht sehr intuitiv, dass ein erfolgreiches 'Load' ein false bei 'IsLoaded' nach sich ziehen kann.
    War auch nur ein Beispiel, vielleicht passt es hier gerade wirklich nicht; häufig wäre das aber eine passende (passendere) Alternative.



  • Ishildur schrieb:

    Da hast du zu 100% recht, daher schreibe ich auch immer eine Default Teilimplementierung, bspw. AbstractResource, welche genau diese Aufgaben übernimmt.

    Und warum gibt es dann IResource wenn es eh AbstractResource gibt? Sollen doch alle davon erben, spart massig Aufwand.

    In Java macht man das so, weil es nicht anders geht, in C++ erbt man einfach von AbstractResource und gut.



  • Und warum gibt es dann IResource wenn es eh AbstractResource gibt?

    Damit man immer noch die Möglichkeit hat eine Implementierung zu schreiben, welche die Standardaufgaben anders löst als AbstractResource.



  • Ishildur schrieb:

    Und warum gibt es dann IResource wenn es eh AbstractResource gibt?

    Damit man immer noch die Möglichkeit hat eine Implementierung zu schreiben, welche die Standardaufgaben anders löst als AbstractResource.

    Sie ist doch abstract 😉



  • Ishildur schrieb:

    Irgendwie hab ich das Gefühl, du hast nicht verstanden, wozu virtual Vererbung in C++ da ist.

    Wie gesagt ich masse mir nicht an alles zu wissen und zu verstehen, ich lerne gerne dazu 🙂
    Es gibt natürlich probleme, wenn nun zwei Interfaces eine Methode mit demselben Namen sowie derselben Signatur anbieten.
    [/cpp]

    Nich ganz.
    http://en.wikipedia.org/wiki/Virtual_inheritance
    Oder kurz: Damit eine Basisklasse nur einmal in einer Derivedklasse landet, die von 2 Klassen erbt, die von der Basis erben.



  • Sie ist doch abstract 😉

    Also hat sie members, welche (mit grosser Wahrscheinlichkeit) von der alternativen Implementierung nicht benötigt werden 😉



  • @jokester
    Ja diesen Artikel kenne ich mittlerweile auch (seit gestern 17:08) als das erste mal der Begriff "Virtuell Erben" gefallen ist 😉

    Aber ist denn virtuelle Vererbung von Klassen, welche ausschliesslich pure virtuelle Methoden beinhaltet nicht mit den C# und Java interfaces identisch?


  • Administrator

    Selfquote:

    Dravere schrieb:

    Übrigens: Wieso gibst du bei GetName das std::string Objekt als Zeiger zurück? Ist auch einer der Indikatoren, dass du anscheinend ziemlich viel mit new anlegst.

    Würde mich noch interessieren 😉

    Ishildur schrieb:

    Ich denke, dafür is virtuelle Verwebung da, damit die Methode GetName nicht doppeldeutig ist. Ich will ja nicht, dass MyObjekt dem Logger und dem Skriper zwei unterschiedliche Namen zurückgibt.

    Du hast virtual Vererbung definitiv nicht verstanden. Eine virtual Vererbung geschieht auf der Ebene der Klasse/Objekt. Mit Methoden aus zwei unterschiedlichen Klassen hat das nichts zu tun. Bei deinem Beispiel kannst du virtual auch gleich weglassen bei der Vererbung.

    Wenn du zwei Methoden mit gleichen Namen aus unterschiedlichen Klassen hast, welche auch eine Implementation aufweisen (also nicht pure virtual sind), dann hilft auch die virtual Vererbung nichts mehr. Beim Aufruf einer solchen Methode, musst du dann explizit angeben, welche du aufrufen möchtest.

    Ishildur schrieb:

    Sie ist doch abstract 😉

    Also hat sie members, welche (mit grosser Wahrscheinlichkeit) von der alternativen Implementierung nicht benötigt werden 😉

    Und mit welcher Wahrscheinlichkeit tritt dieser Fall auf?

    Grüssli



  • Ishildur schrieb:

    Sie ist doch abstract 😉

    Also hat sie members, welche (mit grosser Wahrscheinlichkeit) von der alternativen Implementierung nicht benötigt werden 😉

    Verstehe ich nicht. Welche Member sollte sie denn haben? Kann mir nicht vorstellen dass das oft vorkommt - also bei mir zB noch nie.

    Weil du dann ja recht schnell konkret wirst und nicht mehr abstrakt bist...

    worum es aber eigentlich geht: dein code sieht wie java code und nicht wie c++ code aus.



  • @Shade Of Mine
    Hahaha, in den Java Foren jammern sie, mein Code sehe wie C/C++ Code aus :p



  • brigens: Wieso gibst du bei GetName das std::string Objekt als Zeiger zurück? Ist auch einer der Indikatoren, dass du anscheinend ziemlich viel mit new anlegst.
    

    Nein ich will nur nicht, dass der string jedes Mal kopiert wird, wenn ich einen Namen abfrage 😉



  • Ishildur schrieb:

    Aber ist denn virtuelle Vererbung von Klassen, welche ausschliesslich pure virtuelle Methoden beinhaltet nicht mit den C# und Java interfaces identisch?

    Hat nichts miteinander zu tun. C++ virtual vererbung ist wirklich nur fuer den deadly diamond.


  • Administrator

    Ishildur schrieb:

    @Shade Of Mine
    Hahaha, in den Java Foren jammern sie, mein Code sehe wie C/C++ Code aus :p

    Spricht nicht gegen die Aussage von Shade Of Mine. Kann gut sein, dass du ein Stil für C++ und Java anwendest, was definitiv falsch ist. Man muss für jede Sprache anders programmieren. Oder du programmierst in Java wirklich wie in C++ und in C++ wie in Java. Dann solltest du auf beides mal ein std::swap anwenden 😉

    Grüssli


  • Mod

    Ishildur schrieb:

    brigens: Wieso gibst du bei GetName das std::string Objekt als Zeiger zurück? Ist auch einer der Indikatoren, dass du anscheinend ziemlich viel mit new anlegst.
    

    Nein ich will nur nicht, dass der string jedes Mal kopiert wird, wenn ich einen Namen abfrage 😉

    Dafür benutzt man eigentlich Referenzen...


Anmelden zum Antworten