Vorheriges Thema anzeigen :: Nächstes Thema anzeigen |
Autor |
Nachricht |
Jonathan_Klein Living Legend
Alter: 37 Anmeldedatum: 17.02.2003 Beiträge: 3433 Wohnort: Siegerland Medaillen: Keine
|
Verfasst am: 08.11.2005, 13:21 Titel: Singletons |
|
|
Was ist das?
Klassen von den man nur 1 Objekt erstellen kann.
Was soll das?
Von vielen Klassen braucht man nur ein Objekt. Zum Beispiel eien Klasse die logbücher schreibt oder D3D verwaltet. Mit Singletons muss man nicht globale Objekte erstellen oder an alle Kasse Objektzeiger weitergeben. Außerdem könnte es gar zu Fehlern kommen, wenn zum Beispiel 2 D3D Klassen paralel laufen würden.
Wie geht das?
Ganz einfach. Du musst nur den/die Konstruktor/Konstruktoren privat machen. In etwa so:
CPP: | class Logbook
{
public:
Entry(char* Text);
private:
Logbook();
}
|
Dann kannst du keine Objekte mehr erstellen, weil nur die Klasse auf ihren Konstruktor zugriff hat. Dann braucsht du noch ein solche public-Funktion:
CPP: | static Logbook& Logbook::GetInstance()
{
static Logbook theInstance;
return theInstance;
}
|
Jetzt kann jede Datei die die "Logbook.h" includiert über folgenden Befehl auf das Logbook zugreifen:
CPP: | #include "logbook.h"
Logbook::GetInstance().Entry("juhu, es klappt!");
|
_________________ https://jonathank.de/games/ |
|
Nach oben |
|
|
Patrick Dark JLI Master
Anmeldedatum: 25.10.2004 Beiträge: 1895 Wohnort: Düren Medaillen: Keine
|
Verfasst am: 08.11.2005, 13:38 Titel: |
|
|
Ich glaube viele haben Probleme nur mit nem bissel Code, könntest Du das ggf. mit ner kompletten Header machen und Sourcedatei (ohne D3D, DD, OGL oder DI implementierung).
würde dem verständis mehr dienen. _________________ 'Wer der Beste sein will muss nach Perfektion streben und jede Gelegenheit nutzen sich zu verbessern.' - KIA
[ German Game Dev | Boardsuche hilft sehr oft | Google rockt | Wie man Fragen richtig stellt | ICQ#: 143040199 ] |
|
Nach oben |
|
|
Dr. Best Senior JLI'ler
Alter: 34 Anmeldedatum: 17.06.2004 Beiträge: 269 Wohnort: Köln Medaillen: Keine
|
Verfasst am: 08.11.2005, 13:50 Titel: |
|
|
Also ich hab noch nie was davon gehört aber es jetzt sofort verstanden.
Hört sich ganz praktisch an.
Ne Performanceverbesserung bringt das aber nicht mit sich oder? _________________
Ich bin da, wer noch? |
|
Nach oben |
|
|
Jonathan_Klein Living Legend
Alter: 37 Anmeldedatum: 17.02.2003 Beiträge: 3433 Wohnort: Siegerland Medaillen: Keine
|
Verfasst am: 08.11.2005, 13:53 Titel: |
|
|
^^
Naja, dürfte Speicherplatz sparen, GetInstance könnte man bestimmt auch inline machen, dürfte aber kein Großer Unterschied sein. Da kann man an anderen Stellen mehr optimieren. _________________ https://jonathank.de/games/ |
|
Nach oben |
|
|
PeaceKiller JLI Master
Alter: 35 Anmeldedatum: 28.11.2002 Beiträge: 970
Medaillen: Keine
|
|
Nach oben |
|
|
Christian Rousselle Site Admin
Alter: 48 Anmeldedatum: 19.07.2002 Beiträge: 1630
Medaillen: Keine
|
Verfasst am: 20.05.2006, 13:10 Titel: |
|
|
Nachdem ich schon häufiger Probleme mit dem Singleton-Entwurfsmuster hatte, poste ich jetzt mal eine Lösung, die (hoffentlich) mit Visual C++ (6, 7, 7.1, 8) funktioniert.
CPP: | #pragma once
template <typename T> class CSingleton
{
public:
static T& GetInstance()
{
return m_Instance;
}
static T* GetInstancePtr()
{
return &m_Instance;
}
protected:
CSingleton()
{
}
static T m_Instance;
virtual ~CSingleton()
{
}
};
template <typename T> T CSingleton <T>::m_Instance;
|
Eigentlich ist es schöner, wenn man die statische Variable direck in der GetInstance()-Methode erzeugt:
CPP: | static T& GetInstance()
{
static T m_Instance;
return m_Instance;
}
|
Das macht jedoch mit Visual C++ Probleme (unterschiedliches Verhalten im Debug/Releasemode - scheinbar ist auch nicht wirklich geklärt, wie es sich nach dem Standard korrekt verhalten sollte), deshalb habe ich die oben gezeigte Implementierung gewählt. Außerdem kann man, bei der Lösung mit statischer Variable in der Methode keine GetInstancePtr()-Methode verwenden. Diese Methode gibt es aber nur aus Komfortgründen.
Wenn jetzt eine Singleton-Klasse erzeugt werden soll, z.B. einen ResourceManager, den man typischerweise nur einmal im Programm benötigt, sieht die Definition so aus:
CPP: | class CResourceManager : public CSingleton<CResourceManager>
{
// ...
}; |
Wenn jemand Probleme damit hat, bitte melden. |
|
Nach oben |
|
|
David Super JLI'ler
Alter: 39 Anmeldedatum: 13.10.2005 Beiträge: 315
Medaillen: Keine
|
Verfasst am: 10.07.2006, 21:52 Titel: |
|
|
Diese Lösung beschränkt sich allerdings auf den Standardkonstruktor der jeweiligen Klasse.
Das kann man zwar mehr oder weniger ausbügeln, es ist aber dennoch eine Einschränkung, was nicht gerade schön ist. Außerdem kann man weitere Instanzen aus der abgeleiteten Klasse bilden, was auch gegen den Sinn von Singletons spricht.
Besser wäre etwas wie:
CPP: | template< class T >
class TSingleton
{
protected:
static T *m_instance;
public:
TSingleton()
{
assert( !m_instance );
m_instance = static_cast< T* >( this );
}
~TSingleton()
{
assert( m_instance );
m_instance = 0;
}
static T &GetInstance()
{
return *m_instance;
}
static T *GetInstancePtr()
{
return m_instance;
}
};
|
Verwendet würde das folgendermaßen:
CPP: | class Foo : public TSingleton< Foo >
{
private:
int x;
public:
static Foo &GetInstance();
static Foo *GetInstancePtr();
};
template<> Foo* TSingleton< Foo >::m_instance = 0;
Foo &Foo::GetInstance()
{
return *m_instance;
}
Foo *Foo::GetInstancePtr()
{
return m_instance;
}
#define g_foo Foo::GetInstancePtr()
|
Nun muss natürlich eine Instanz erzeugt werden. Ansonsten läuft das ganze nicht.
CPP: | int main()
{
Foo bar;
// whatever
g_foo->whatever( ... )
return 0;
}
|
Durch die assert ist sichergestellt das wirklich nur ein Objekt der Klasse existiert. Daher muss der Konstruktor auch nicht protected sein.
grüße |
|
Nach oben |
|
|
Otscho Super JLI'ler
Alter: 36 Anmeldedatum: 31.08.2006 Beiträge: 338 Wohnort: Gummibären-Gasse Medaillen: Keine
|
Verfasst am: 11.06.2007, 12:53 Titel: |
|
|
Wenn ich ein Singleton mache wie, im ersten Beispiel von Jonathan_Klein, wird dann automatisch eine Instance erzeugt und wird da der Konstruktor und Destruktor aufgerufen ? |
|
Nach oben |
|
|
Maxim Senior JLI'ler
Anmeldedatum: 28.03.2004 Beiträge: 249
Medaillen: Keine
|
Verfasst am: 11.06.2007, 15:28 Titel: |
|
|
nein, du musst ein mal die instanz erstellen und danach kannst du es überall in dem code verwenden.
natürlich kannt du die singleton klasse auch so abändern, dass sie automatisch eine instanz erzeugt, wenn nötig ist, das ist aber keine gute idee, da dann deine singleton-klassen immer einen standardkonstruktor enthalten müssen und das macht ja nicht bei allen klassen sinn. |
|
Nach oben |
|
|
Otscho Super JLI'ler
Alter: 36 Anmeldedatum: 31.08.2006 Beiträge: 338 Wohnort: Gummibären-Gasse Medaillen: Keine
|
Verfasst am: 11.06.2007, 15:55 Titel: |
|
|
Ok ich hab jetzt ein Singlton geschrieben. Nur reagiert es nur wenn es von der Main.cpp angesprochen wird wenn ich von einer anderen Klasse aus versuch seine Funktionen aufzurufen reagiert es überhauptnicht hier mal der Header des Singltons CPP: | #ifndef LOGBOOKFILE
#define LOGBOOKFILE
#include <windows.h>
#include <iostream>
#include <cstdio>
class Logbook
{
public:
static Logbook& Logbook::GetInstance() {
static Logbook theInstance;
return theInstance;
}
void Init(void);
void Close(void);
void Succed(char* location, char* reason);
void Error(char* location, char* reason);
void Warning(char* location, char* reason);
private:
Logbook();
virtual ~Logbook();
FILE *Datei;
};
#endif |
Und der Zugriff per CPP: | Logbook::GetInstance().Succed(reinterpret_cast<char*>(&"Testarea"), reinterpret_cast<char*>(&"Testreason")); |
Weiß jemand was ich falsch mache ? |
|
Nach oben |
|
|
Maxim Senior JLI'ler
Anmeldedatum: 28.03.2004 Beiträge: 249
Medaillen: Keine
|
Verfasst am: 11.06.2007, 16:13 Titel: |
|
|
was machst du da
meine singletonklasse:
CPP: | /********************************************************************
CSingleton.h
===========
Diese Datei ist ein modifizierter Teil der Positron-Gun Engine.
Beschreibung:
Alle von dieser abgeleitete Klassen konnen nur einmal instanziert werden und
man bekommt uberall den Zugriff auf diese Klassen ohne irgendwelchen
Zeiger ubergeben zu mussen.
Ist sehr pratisch fur Ressourcen-Manager.
Verwendung an Beispiel einer Klasse names A:
1. Die Klasse A von dieser Klasse ableiten.
z.B.
class CTextureManager
: public Singleton<CTextureManager>
{
void GetTexture();
};
2. Eine Instanz von Klasse A irgendwo im Code erstellen.
z.B. CTextureManager tman;
3. Ab jetzt kann man ueberall auf die Klasse mit A::GetSingleton() zugreifen.
CTextureManager::GetSingleton().GetTexture();
oder
CTextureManager::GetSingletonPtr()->GetTexture();
und dass in jedem teil des codes bzw. der cpp datei
globale Variablen z.B. für TextureManager oder RenderKlasse fallen weg
Zu letzt bearbeitet am:
25.10.2005
Autor:
Maxim
********************************************************************/
#pragma once
#include <cassert>
template <typename T>
class CSingleton
{
static T* ms_Singleton;
protected:
CSingleton(void)
{
if(!ms_Singleton == 0)
{
assert( !ms_Singleton);
return;
}
#if defined( _MSC_VER ) && _MSC_VER < 1200
int offset = (int)(T*)1 - (int)(Singleton <T>*)(T*)1;
ms_Singleton = (T*)((int)this + offset);
#else
ms_Singleton = static_cast< T* >( this );
#endif
}
public:
~CSingleton(void)
{
assert(ms_Singleton);
ms_Singleton = 0;
}
static T& GetSingleton(void)
{
assert(ms_Singleton);
return (*ms_Singleton);
}
static T* GetSingletonPtr(void)
{
assert(ms_Singleton);
return ms_Singleton;
}
};
template <typename T> T* CSingleton <T>::ms_Singleton = 0; |
|
|
Nach oben |
|
|
Dragon Super JLI'ler
Alter: 38 Anmeldedatum: 24.05.2004 Beiträge: 340 Wohnort: Sachsen Medaillen: Keine
|
Verfasst am: 11.06.2007, 17:33 Titel: |
|
|
Zitat: | Weiß jemand was ich falsch mache ? |
Ja, und so sollte es funktionieren:
CPP: | #ifndef LOGBOOKFILE
#define LOGBOOKFILE
#include <windows.h>
#include <iostream>
#include <cstdio>
class Logbook
{
public:
static Logbook& GetInstance() // so und nicht anders ;)
{
static Logbook theInstance;
return theInstance;
}
void Init(void);
void Close(void);
void Succed(const char* location, const char* reason); // nimm lieber const-char
void Error(const char* location, const char* reason);
void Warning(const char* location, const char* reason);
private:
Logbook();
virtual ~Logbook();
FILE *Datei;
};
#endif |
CPP: | // Hier muss nichts gecastet werden! Warum machst du das überhaupt?
Logbook::GetInstance().Succed("Testarea", "Testreason"); |
Gruß Sven _________________ Nur wenn man ein Ziel sieht, kann man es auch treffen.
___________
Mein Leben, Freunde und die Spieleentwicklung |
|
Nach oben |
|
|
DirectXer Dark JLI'ler
Anmeldedatum: 05.02.2005 Beiträge: 1201 Wohnort: Köln Medaillen: Keine
|
Verfasst am: 11.06.2007, 18:27 Titel: |
|
|
ein guter link zum thema singleton ist u.a. dieser hier; da wird eine Singleton-Klasse von Grund auf erzeugt, sodass jeder das Konzept und die "Tricks" verstehen müsste
Gruß DXer |
|
Nach oben |
|
|
Otscho Super JLI'ler
Alter: 36 Anmeldedatum: 31.08.2006 Beiträge: 338 Wohnort: Gummibären-Gasse Medaillen: Keine
|
Verfasst am: 11.06.2007, 19:20 Titel: |
|
|
Danke für eure Tipps.
Jetzt gehts |
|
Nach oben |
|
|
Otscho Super JLI'ler
Alter: 36 Anmeldedatum: 31.08.2006 Beiträge: 338 Wohnort: Gummibären-Gasse Medaillen: Keine
|
Verfasst am: 16.04.2009, 08:17 Titel: |
|
|
Besteht auch die Möglichkeit ein Interface für Singletons zu erstellen ? |
|
Nach oben |
|
|
|