Problem mit Software Architektur (C++)



  • Fedaykin schrieb:

    class IWrong
    {
       DoWrong()
       {
          ....
       }
    }
    
    class IWrong1: IWrong
    {
    
    }
    
    class Wrong :public IWrong, IWrong1
    {
       //Hier haben wir auf einmal DoWrong 2 mal.
    }
    

    Ich hab sowas noch nicht versucht. Ob das wirklich das Problem ist kann ich nicht sagen. Ich könnte mir vorstellen das sowas Probleme auslösen kann.

    Nö, das verursacht keine Probleme. Wieso sollte es auch? DoWrong() ist weder in IWrong1, noch in Wrong verfügbar.



  • Falls du "Effective C++" zu Hause hast, dann lies mal Item 40. Dort wird das Problem mit dem "deadly MI diamond".

    Versuch mal das hier:

    class IResourceService: virtual public IService{ 
     // einige zusätzliche Dinge... 
    }; 
    
    class AbstractService: virtual public IService{ 
     // implentiert gewisse Verwaltungsaufgaben die in den allermeisten Services anfallen... 
    };
    

    PS:
    Ich weiss nicht obs funktioniert 😉



  • Ishildur schrieb:

    Sollte die virtuelle Verwerbung nicht genau dieses Problem beseitigen?

    Hab ich ja gleich zu Beginn geschrieben. Daran liegt's und so lässt sich's lösen.



  • Es funktioniert so halbers. Er kompilierts zwar, jedoch nur wiederwillig:

    1>c:\users\samuel\desktop\projekte\serenity\serenity\development\serenity\ShaderResource.h(206) : warning C4250: 'PixelShaderResource' : inherits 'AbstractResource::AbstractResource::IsLoaded' via dominance
    1> c:\users\samuel\desktop\projekte\serenity\serenity\development\serenity\Resource.h(194) : see declaration of 'AbstractResource::IsLoaded'

    Er gibt ca. 5000 solche Warnungen aus...


  • Administrator

    Ishildur schrieb:

    Also ja, das verursacht in C++ auch Probleme

    Was genau bedeutet das? Kannst du mir einige Beispiele geben, wo es Probleme macht und wie sich diese auswirken?

    Ich wollte eigentlich darauf hinaus. Nehmen wir zum Beispiel C#:

    public interface IFoo
    {
      void bar();
    }
    
    public class Base
      : IFoo
    {
      public void bar() { }
    }
    
    public class Derived
      : Base, IFoo
    {
      // null problemo
    }
    

    Wenn du dies nun 1:1 auf C++ überträgst:

    class IFoo
    {
    public:
      virtual void bar() = 0;
    };
    
    class Base
      : public IFoo
    {
    public:
      void bar() { }
    };
    
    class Derived
      : public Base
      , public IFoo
    {
      // Nun hast du plötzlich zweimal die Funktion bar und eine davon ist rein virtuell
    };
    

    Und ja, wenn du von IFoo virtuell erbst, dann besteht dieses Problem nicht mehr:

    class IFoo
    {
    public:
      virtual void bar() = 0;
    };
    
    class Base
      : virtual public IFoo
    {
    public:
      void bar() { }
    };
    
    class Derived
      : public Base
      , virtual public IFoo
    {
      // Alles klar
    };
    

    Grüssli



  • Gibt es einen Grund, nicht einfach pauschal alles virtuell zu erben?



  • Ishildur schrieb:

    Es funktioniert so halbers. Er kompilierts zwar, jedoch nur wiederwillig:

    1>c:\users\samuel\desktop\projekte\serenity\serenity\development\serenity\ShaderResource.h(206) : warning C4250: 'PixelShaderResource' : inherits 'AbstractResource::AbstractResource::IsLoaded' via dominance
    1> c:\users\samuel\desktop\projekte\serenity\serenity\development\serenity\Resource.h(194) : see declaration of 'AbstractResource::IsLoaded'

    Er gibt ca. 5000 solche Warnungen aus...

    Prinzipiell ists erstmal eine Warnung. Ich denke wenn es genügend Interfaces existieren die über diese Virtuelle Vererbung arbeiten sind die Warnungen soviel.

    Ich kann aber nicht genau sagen ob es möglichkeiten gibt diese Warnungen weg zu bekommen.



  • Hehe, da kann Abhilfe geschaffen werden:

    // ###################### disable stupid and useless compiler - warnings ######################
    // --------------------------------------------------------------------------------------------
    #pragma warning(disable:4100) // unreferenced formal parameter [unused method parameters]
    #pragma warning(disable:4127) // conditional expression is constant [while(true)]
    #pragma warning(disable:4482) // nonstandard extension used: enum
    #pragma warning(disable:4706) // assignment within conditional expression
    #pragma warning(disable:4715) // not all control paths return a value
    #pragma warning(disable:4701) // potentially uninitialized local variable used
    #pragma warning(disable:4238) // nonstandard extension used : class rvalue used as lvalue
    #pragma warning(disable:4996) // 'stricmp': The POSIX name for this item is deprecated.
    #pragma warning(disable:4250) // inheritance via dominance (diamond of death with interfaces)
    // --------------------------------------------------------------------------------------------
    // ############################################################################################
    

    Dieser Block steht bei mir ziemlich weit oben in der main header datei. :p
    Siehe insbesondere die unterste Zeile...


  • Administrator

    Ishildur schrieb:

    Es funktioniert so halbers. Er kompilierts zwar, jedoch nur wiederwillig:

    1>c:\users\samuel\desktop\projekte\serenity\serenity\development\serenity\ShaderResource.h(206) : warning C4250: 'PixelShaderResource' : inherits 'AbstractResource::AbstractResource::IsLoaded' via dominance
    1> c:\users\samuel\desktop\projekte\serenity\serenity\development\serenity\Resource.h(194) : see declaration of 'AbstractResource::IsLoaded'

    Er gibt ca. 5000 solche Warnungen aus...

    Das heisst, dass du IsLoaded zweimal definiert hast, wegen der virtuellen Vererbung allerdings nur eines genommen wird. Daher womöglich die Funktionalität einer Klasse verändert werden könnte. Zeig mal kurz die Klassen und wie sie in Relation stehen, bzw. wer alles IsLoaded definiert. Das riecht ein wenig seltsam 😉

    Ishildur schrieb:

    Gibt es einen Grund, nicht einfach pauschal alles virtuell zu erben?

    Weil man es vielleicht gar nicht möchte? Man muss sich das immer ganz genau überlegen. Am besten verzichtet man aber auf solche Konstrukte gleich vollständig. Bei mir kommt sowas äusserst selten vor. Zudem kann die Performance etwas darunter leiden, wenn ich mich recht erinnere.

    Grüssli



  • @Dravere
    Die Methode IsLoaded ist 100% ausschliesslich in der Klasse AbstractResource definiert!!! 😉



  • Ishildur schrieb:

    Gibt es einen Grund, nicht einfach pauschal alles virtuell zu erben?

    Java und C# machen das ganze prinzipiell ja so. C++ hat aber andere Ansprüche. Wie schon angesprochen ist Virtuelle Verwerbung etwas langsamer da in einer Tabelle erstmal geschaut werden muss welche Funktion nun wirklich aufgerufen werden soll. Zusätzlich benötigt diese Tabelle auch noch Speicher. Bei eimen QuadCore mit 2,8 GHz und 1 Terrabyte Ram sicherlich kein Problem. Für ein Embedded System mit ein paar wenigen MHz und sehr sehr wenig Ram sicherlich problematisch.



  • Ich habe nun noch so eine eigenartige Warnung erhalten, mit der ich nichts anfangen kann und die vielleicht in diesem Zusammenhang steht?

    // *************************** interface "IHeightmapResourceFactory" **************************
    // This interface extends the IResourceFactory interface for creating new instances of
    // classes implementing the IHeightmapResource interface (covariance).
    // Author: Samuel Lörtscher
    // ********************************************************************************************
    class IHeightmapResourceFactory:public virtual IResourceFactory{
    public:
     // ------------------------------------ interface methods ------------------------------------
     virtual IHeightmapResource *NewInstance(uint32 Param) = 0;
     // -------------------------------------------------------------------------------------------
    };
    // ********************************************************************************************
    
    // ***************************** class "HeightmapResourceFactory" *****************************
    // This class is a concrete implementation of the IHeightmapResourceFactory interface.
    // Author: Samuel Lörtscher
    // ********************************************************************************************
    class HeightmapResourceFactory:public IHeightmapResourceFactory{
    private:
     // --------------------------------- private dynamic members ---------------------------------
     float32 sMap; // the size of the entire map
     float32 sHgt; // the maximal height (mapping between uint16 and float32)
     // -------------------------------------------------------------------------------------------
    public:
     // ------------------------------- constructors and destructor -------------------------------
     HeightmapResourceFactory(float32 MapSize,float32 Height);
     ~HeightmapResourceFactory(void){}
     // -------------------------------------------------------------------------------------------
    
     // ---------------------------------- public dynamic methods ---------------------------------
     HeightmapResource *NewInstance(uint32 Param);
     string            *GetName(void) const;
     // -------------------------------------------------------------------------------------------
    };
    // ********************************************************************************************
    

    Nun bekomme ich folgende Warnung:

    1>c:\users\samuel\desktop\projekte\serenity\serenity\development\serenity\heightmapresource.h(63) : warning C4505: 'IHeightmapResourceFactory::NewInstance' : unreferenced local function has been removed

    Ähmm.... hääää??? 😕



  • Das bedeutet, dass die Funktion NewInstance nicht referenziert/verwendet wird und der Linker sie deshalb entfernt hat.



  • In deiner Klasse IHeightmapResourceFactory hast du eine abstrakte Funktion deklariert. Diese muss in der abgeleiteten Klasse implmenetiert werden, was du allerdings nicht tust.



  • Diese muss in der abgeleiteten Klasse implmenetiert werden, was du allerdings nicht tust.

    Doch tue ich doch???

    P.S.
    Aha, ich muss vielleicht noch sagen, dass HeightmapResource eine konkrete implementierung von IHeightmapResource ist. Daher gelten die Regeln der Kovarianz...



  • Ishildur schrieb:

    Hehe, da kann Abhilfe geschaffen werden:
    ... disable stupid and useless compiler - warnings

    Viele der von dir auskommentierten Warnungen würde ich in einem realen Projekt niemals auskommentieren, und sehe ich in der Regel nicht nur als Warnung, sondern als Fehler an.

    Ich hoffe jedenfalls nicht, das man diesen Block ohne nachzudenken einfach in seinen Code kopiert. Es gibt zwar Fälle, in denen ich Warnungen deaktiviere, aber dann so lokal wie möglich und nur nach vorheriger Prüfung - Jede Warnung sollte man sich erst einmal zu Herzen nehmen, und dann prüfen ob sie in diesem Fall berechtigt ist (Und möglichst maximal auf Dateiebene deaktivieren, wenn nicht gar auf Blockebene).



  • @Nukularfüsiker
    Seit wann kann ein linker Pure Virtual Functions entfernen?



  • @asc
    Welche Warnung meinst du konkret, die man nicht einfach ausschalten sollte?

    #pragma warning(disable:4100) // unreferenced formal parameter [unused method parameters]
    

    Viele Interfaces erwarten Parameter, welche jedoch von einigen konkreten Implementierungen nicht genutzt werden.

    #pragma warning(disable:4127) // conditional expression is constant [while(true)]
    

    Oft hat man keine Ahnung, wie oft eine schleife durchlaufen wird, sie wird mit einem break verlassen.

    #pragma warning(disable:4482) // nonstandard extension used: enum
    

    Ja genau, ich darf keine enums benutzen

    #pragma warning(disable:4706) // assignment within conditional expression
    

    Muss ich die Methode wie strlen usw. 2mal aufrufen, einmal für den Test und dann noch einmal für die effektive Zuweisung (genau!)

    #pragma warning(disable:4715) // not all control paths return a value
    

    Methoden, welche einen return value != void haben und eine exception werfen, werden nicht mehr kompiliert.

    #pragma warning(disable:4701) // potentially uninitialized local variable used
    

    Vielfach hat man variablen, welche man mit Werten aus einer Datei oder anderen Datenquellen füllt, diese dann vorher noch explizit mit null zu füllen, nur um sich gleich anschliessend auf der nächsten Zeile wieder zu überschreiben. Naja....

    #pragma warning(disable:4238) // nonstandard extension used : class rvalue used as lvalue
    

    SetVector(&Vector3(0.0f,0.0f,0.0f))
    Was soll daran falsch sein?

    #pragma warning(disable:4996) // 'stricmp': The POSIX name for this item is deprecated.
    

    Und wie lautet der richtige Name? Habe ich nirgends gefunden...

    #pragma warning(disable:4250) // inheritance via dominance (diamond of death with interfaces)
    

    Hier sage ich mal nichts, weil habe diese Zeile erst vorhin hinzugefügt und weiss noch nicht, was das für Konsequenzen haben wird...



  • OMG 😮



  • OMG? 😃


Anmelden zum Antworten