Alternative für globale Variablen
-
Ja, nur müsste ich dann wieder eine neue Klasse erstellen. Ich habe das nun folgendermaßen probiert, was mir jedoch eine Fehlermeldung gibt:
class MainClass { public: MainClass(); ~MainClass(); void LoadSettings(); protected: static bool bsetting; static int isettingvalue; //... }; MainClass::MainClass() { } MainClass::~MainClass() { } void MainClass::LoadSettings() { //Settings laden //<-- Code hier --> bsetting = true; } int main() { MainClass mClass; mClass.LoadSettings(); return 0; }TestProject.obj : error LNK2001: unresolved external symbol "protected: static bool MainClass::bsetting" (?bsetting@MainClass@@1_NA) 1>TestProject.exe : fatal error LNK1120: 1 unresolved externalsWie kann ich den Variablen denn nun einen Wert zuweisen? Natürlich könnte ich sich public machen und das dann außerhalb der Funktion machen, aber dann kann ich auch die globalen Variablen behalten.
-
guck dir mal singletons an - so geht das mit sicherheit nicht...
tip:
static_variablen_typ meineklasse::static_variable;
außerhalb der klasseund leeren Ctor und Dtor brauchste auch nich selbst implementieren, das macht der compiler schon für dich

bb
-
Ich habe ein wenig gegoogelt und die Lösung gefunden: http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.11. Nun funktioniert es, wenn ich
bool MainClass::bsetting = true;außerhalb der Klasse/Funktion schreibe. Auch innerhalb einer Funtkion lässt es sich nun anwenden. Eigentlich habe ich nun erreicht, was ich wollte. Sollte ich dennoch zu einer Singleton Klasse greifen, bzw. hat dieser Weg irgendwelche erheblichen Nachteile?#include "stdafx.h" #include "TestProject.h" class MainClass { public: MainClass(); ~MainClass(); void LoadSettings(); protected: static bool bsetting; static int isettingvalue; //... }; MainClass::MainClass() { } MainClass::~MainClass() { } bool MainClass::bsetting = true; void MainClass::LoadSettings() { bsetting = false; } int main() { MainClass mClass; mClass.LoadSettings(); return 0; }
-
Naja. Du kannst unsinnigerweise das hier machen:
int main() { MainClass mClass; mClass.LoadSettings(); MainClass mClass2; mClass2.LoadSettings(); return 0; }Macht nicht viel Sinn, da nur eine Instanz der Klasse
MainClassSinn macht, oder? - Dann ist das schon ein Fall für ein Singleton. Oder mach wenigstens auch die Funktionen der Klasse statisch und den Konstruktor privat. Dann hast du einen ähnlichen Effekt.
-
Erstmal vielen Dank für die Hilfe. Ich habe nun folgendes versucht, bekomme aber noch zwei Fehlermeldungen.
class Settings { private: //Ein Pointer zum Speichern der Instanz static Settings* instance; //Konstruktor private, damit man sich keine Instanzen holen kann. Settings(std::string FileName) { m_FileName = FileName; } std::string m_FileName; //Den Kopierkonstruktor schützen um zu vermeiden, dass das Objekt unbeabsichtigt kopiert wird. Settings(const Settings& cc){} ~Settings(){} public: static Settings* getInstance(std::string FileName); static void Destroy(); void LoadSettings(); bool bsetting; int isettingvalue; }; Settings* Settings::instance = NULL; Settings* Settings::getInstance(std::string FileName) { if( !instance ) instance = new Settings(FileName); return instance; } void Settings::Destroy() { // static if (instance){ delete instance; instance = NULL; } } void Settings::LoadSettings() { //Code zum Laden der Settings // ------------------------- bsetting = true; isettingvalue = 5; } class MainClass : public Settings { public: MainClass(); ~MainClass(); void TestMainClass(); //... }; void MainClass::TestMainClass() { std::cout << "settingvalue from maincalss = " << isettingvalue; std::cin.get(); } int main() { Settings *settings = Settings::getInstance("mysettings.ini"); settings->LoadSettings(); //Ausgabe: 5 (ohne MainClass getestet) std::cout << "settingvalue = " << settings->isettingvalue; std::cin.get(); MainClass mClass; mClass.TestMainClass(); // Destroy instances Settings::Destroy(); return 0; }1>TestProject.obj : error LNK2019: unresolved external symbol "public: __thiscall MainClass::~MainClass(void)" (??1MainClass@@QAE@XZ) referenced in function _main 1>TestProject.obj : error LNK2019: unresolved external symbol "public: __thiscall MainClass::MainClass(void)" (??0MainClass@@QAE@XZ) referenced in function _main 1>C:\Users\Wraithin\Documents\Visual Studio 2008\Projects\TestProject\Debug\TestProject.exe : fatal error LNK1120: 2 unresolved externalsWahrscheinlich geht das so wieder nicht, wie ich es mir gedacht habe... Ich habe noch nie etwas mit Singleton Klassen gemacht und deshalb wäre es nett, wenn mir mal kurz jemand helfen könnte.
-
Du kannst von einer Klasse nichts ableiten, wenn kein Konstruktor als public verfügbar ist.. Wenn du das so mit dieser Vererbung machen willst, dann würde ich eher (wiedermal) das Meyers Singleton empfehlen:
http://www.devarticles.com/c/a/Cplusplus/C-plus-plus-In-Theory-The-Singleton-Pattern-Part-I/4/
-
Ich habe mich nun doch dazu entschieden, eine separate Singleton-Klasse namens Settings zu erstellen, was auch soweit ganz gut funktioniert. Da ich die Variablen vorher gerne initialisieren möchte, habe ich mich dazu entschlossen, das direkt im Konstruktor zu machen. Das sollte eigentlich kein Problem darstellen, da ja nur maximal ein Objekt der Klasse erstellt werden kann. Ich weiß, dass mein Code (noch) nicht thread safe ist, aber im Allgemeinen sollte es doch mit der Initialisierung der Variablen im Konstruktor keine Probleme geben, oder?
Hier nochmal der Code:
class Settings { private: //Ein Pointer zum Speichern der Instanz static Settings* instance; //Konstruktor private, damit man sich keine Instanzen holen kann. Settings() { isettingvalue = 12; } //Den Kopierkonstruktor schützen um zu vermeiden, dass das Objekt unbeabsichtigt kopiert wird. Settings(const Settings& cc){} ~Settings(){} public: static Settings* getInstance(); static void Destroy(); void LoadSettings(std::string FileName); bool bsetting; int isettingvalue; }; Settings* Settings::instance = NULL; Settings* Settings::getInstance() { if( !instance ) instance = new Settings(); return instance; } void Settings::Destroy() { if (instance) { delete instance; instance = NULL; } } void Settings::LoadSettings(std::string FileName) { //Code zum Laden der Settings // ------------------------- bsetting = true; isettingvalue = 5; } int main() { Settings *settings = Settings::getInstance(); std::cout << "settingvalue before LoadSettings = " << settings->isettingvalue << std::endl; // Output 12 settings->LoadSettings("testfile.ini"); std::cout << "settingvalue = " << settings->isettingvalue << std::endl; // Output 5 settings->isettingvalue = 2; std::cout << "settingvalue = " << settings->isettingvalue; //Output: 2 std::cin.get(); Settings::Destroy(); return 0; }
-
Und was spricht gegen das Meyers Singleton? - Imo braucht man für ein Singleton das rumhantieren mit dem dynamischen Speicher lediglich, wenn man ein etwas spezielleres Singleton machen will, wie z.B ein Phönix Singleton. Aber ansonsten reicht das von Meyers vorgeschlagene.
Ich finde einfach das hier unnötig und "gefährlich".
Settings::Destroy();
-
Was ist wenn man das Löschen, so wie hier beschrieben:http://www.oop-trainer.de/Themen/Singleton.html, mit einer guard-Klasse macht?
-
Klar kann man. Ich habe das "gefährlich" mit Absicht in Anführungszeichen geschrieben, weil es viele mögliche Implementierungen von Singletons gibt. Oftmals reicht aber Meyers völlig. Und ich bevorzuge eine einfache Lösung, wenn sie passt einer komplizierteren.
Ich sehe den wirklichen Unterschied dieses Guards nicht wirklich zu Meyers. Läuft ja auf das gleiche hinaus. Wenn allerdings der Guard noch zusätzliche Funkitionalität, wie z.B eine manuelle Zerstörung anbietet, dann ist das etwas völlig anderes. Aber, wie gesagt braucht man das ja eher selten und das Meyers Singleton reicht völlig.
-
Oft ist es ideal wenn man Singletons garnicht zerstört.
-
hustbaer schrieb:
Oft ist es ideal wenn man Singletons garnicht zerstört.
Noch öfters ist es ideal, wenn man Singletons garnicht benutzt.
-
hustbaer schrieb:
Oft ist es ideal wenn man Singletons garnicht zerstört.
Wenn nur eines vorhanden ist, dann ist es imo weniger tragisch. Dann zerstört es sich einfach als letztes. Sobald man aber Krieg der Singletons bestreiten will, dann wirds problematisch, wer sich selbst zerstört und wer auf den Leichen rumtrampelt..

-
AntiPatternInc schrieb:
Noch öfters ist es ideal, wenn man Singletons garnicht benutzt.
Vor allem nicht als Alternative zu globalen Variablen.

-
SinglePattern dürfte man Abstand das überbenutzteste Pattern überhaupt sein und es ist nahezu nie angebracht.
Ich finde mittlerweile sogar globale Variablen besser als Singletons.
-
Braunstein schrieb:
Was ist wenn man das Löschen, so wie hier beschrieben:http://www.oop-trainer.de/Themen/Singleton.html, mit einer guard-Klasse macht?
Dann hat man den Fall nicht zuende gedacht.
Warum hat der Wächter nur das Löschen und nicht auch noch das Erzeugen?
In Listing5 fällt die Asymmetrie stark auf.
Hauen wir das Erzeugen doch mal auch in den Wächter-Konstruktor und beobachten, was geschieht.
Es erinnert an was bekanntes. Moment, gleich kommts.
Den instanz-Zeiger und exemplar() auch in den Wächter rein!
Ja, wir habens raus. Es ist ein Meyers-Singleton, der ein gepimpltes Monster-Objekt hält.
-
Wie gesagt. Den Grund so etwas in diese Richtung zu machen, wäre für mich so etwas:
class Singleton { public: static Singleton* exemplar(); private: static Singleton *instanz; Singleton() {} Singleton( const Singleton& ); ~Singleton() {} class Waechter { public: ~Waechter() { if( Singleton::instanz != 0 ) delete Singleton::instanz; } void destroy() { if ( !Singleton::instanz ) { delete Singleton::instanz; Singleton::instanz = 0; } } }; friend class Waechter; };Somit könnte man das Singleton selbst zerstören, wenn das irgendwie notwenig ist, und wenn man es verigsst wird es automatisch gemacht.
-
auchmalanmerker. schrieb:
Ich finde mittlerweile sogar globale Variablen besser als Singletons.
Und ich find Vanilleeis ganz Klasse.
Mal ehrlich: hier sollte es weniger darum gehen was man an persönlichen Präferenzen für und gegen ein bestimmtes Pattern hat, sondern vielmehr darum, welche Vor- und Nachteile das Pattern in der gegebenen Situation gegenüber den Alternativen hat. Deswegen sollte zu jedem "ich finde" auch ein "weil" geliefert werden. Und zwar nicht "weil Vanilleeis einfach lecker ist".
-
Irgendwie versteh ich die Problematik nicht, die es beim Erzeugen/Zerstören geben soll.
Wenn ich das wie im Meyer Singleton mache (also eine Referenz auf eine statische lokale Variable liefere), wo ist dann das Problem?
Erzeugung: Nur wenn man die statische Funktion aufruft, wird das Objekt erzeugt. Passt.
Zerstörung: Ok da bin ich etwas überfragt. Finde eine statische lokale Variable eh irgendwie magisch. Wann wird diese Variable denn wieder zerstört? Und was genau ist jetzt dieses Zerstör-Problem? Kann da vielleicht jemand bitte ein kleines Beispiel bringen?
-
Statische Variablen werden nach dem Ende der main zerstört.
Das Problem ist die Reihenfolge, in der zerstört wird, wenn du 2 statische Variablen hast. Was passiert z.B, wenn die einte zerstört wird und die andere bei seiner eigenen Zerstörung auf die bereits zerstört zugreift?