Problem mit Software Architektur (C++)
-
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...
-
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...
-
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 - warningsViele 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?
-
Ishildur schrieb:
#pragma warning(disable:4100) // unreferenced formal parameter [unused method parameters]
Viele Interfaces erwarten Parameter, welche jedoch von einigen konkreten Implementierungen nicht genutzt werden.
Parameter aus dem Interface rausschmeißen, wenn diese nicht gebraucht werden.
Ishildur schrieb:
#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.
Schlechter Stil. Stattdessen eine bool'sche Variable nutzen.
Ishildur schrieb:
#pragma warning(disable:4482) // nonstandard extension used: enum
Ja genau, ich darf keine enums benutzen
Warum nicht?
Ishildur schrieb:
#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!)
Schlechter Stil. Variable deklarieren und dort zuweisen, dann diese Variable nutzen.
Ishildur schrieb:
#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.
Schlechter Stil. Immer komplette Pfade haben.
Ishildur schrieb:
#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....
Initialisieren. Wird es nicht benutzt, wird es eh wegoptimiert. Und wird es benutzt, beugt man so Fehler vor.
Ishildur schrieb:
#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?Es ist einfach falsch. Erwartet das Ding einen Zeiger? Dann übergib einen Zeiger auf ein richtiges Objekt, kein temporäres. Sonst übergib konkrete Kopien oder eine const Referenz.
Ishildur schrieb:
#pragma warning(disable:4996) // 'stricmp': The POSIX name for this item is deprecated.
Und wie lautet der richtige Name? Habe ich nirgends gefunden...
Welch wunderbar portablen Code du schreibst. :> Schonmal von std::string gehört?
Ishildur schrieb:
#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...
Du entfernst ernsthaft Warnungen, von denen du keine Ahnung hast? Autsch.
-
Ishildur schrieb:
@Nukularfüsiker
Seit wann kann ein linker Pure Virtual Functions entfernen?Das Warum überblicke ich gerade auch nicht, aber das ist es, was die Meldung besagt.
Ishildur schrieb:
@asc
Welche Warnung meinst du konkret, die man nicht einfach ausschalten sollte?Also ich würde ja sagen man sollte zumindest die nicht ausschalten, deren Sinn man nicht genau verstanden hat. Und das ist bei dir bei einigen der genannten der Fall.
Ishildur schrieb:
#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.
for(;;)
bringt keine Warnung.#pragma warning(disable:4482) // nonstandard extension used: enum
Ja genau, ich darf keine enums benutzen
Du hast sicher sowas gemacht:
int foo = Enum::Wert
Es ist aber nicht erlaubt,
Enum::
zu spezifizieren.#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!)
Die Erklärung verstehe ich nicht. Und auch nicht, was strlen in einem C++-Program verloren hat.
#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.
Zeig mal ein Beispiel.
#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.
Das sollte eigentlich keine Warnung verursachen. Zeig mal ein Beispiel.
#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?Ein rvalue hat nun mal keine Adresse.
#pragma warning(disable:4996) // 'stricmp': The POSIX name for this item is deprecated.
Und wie lautet der richtige Name? Habe ich nirgends gefunden...
Eigentliches Problem: du benutzt C-Funktionen in C++.