Hallo,
ich versuche eine Klasse als Kind einer Singleton-Basisklasse zu
erstellen. Meine Kindklasse soll dabei wiederum als Templateklasse
ausgeführt werden. Meine Singleton-Klasse sieht wiefolgt aus:
1
template<classT>
2
classTSingleton
3
{
4
protected:
5
// Membervariablen
6
staticT*m_pSingleton;///< Statisches Objekt
7
public:
8
/**
9
* Destruktor
10
*/
11
virtual~TSingleton()
12
{
13
}
14
15
/**
16
* Get
17
* Aufgabe: Wenn noetig, statisches Objekt erzeugen und Zeiger darauf zurueckgeben!
18
*/
19
inlinestaticT*Get()
20
{
21
// Existiert bereits eine Instanz?
22
if(!m_pSingleton)
23
m_pSingleton=newT;// Nein, dann neue Instanz erzeugen!
24
25
// Zeiger auf die Instanz zurueckgeben!
26
returnm_pSingleton;
27
}
28
29
/**
30
* Statisches Objekt freigeben
31
*/
32
staticvoidDel()
33
{
34
// Existiert die Instanz?
35
if(m_pSingleton)
36
{
37
deletem_pSingleton;// Wenn ja, dann freigeben
38
m_pSingleton=NULL;// und Zeiger auf NULL setzen!
39
}
40
}
41
};
42
43
template<classT>
44
T*TSingleton<T>::m_pSingleton=0;
Die Implementierung klappt auch soweit. Nun will ich jedoch, dass das
Singleton-Objekt wiederum eine Templateklasse ist. Allerdings beschwert
sich der Linker. Die Implementierung sieht dabei wiefolgt aus:
Der Aufruf erfolgt über das Makro "g_pSurface". Der Linker beschwert
sich allerdings, sobald ich eine Memberfunktion der Klasse aufrufen
möchte:
Fehler: undefined reference to `CSurfacemanager<QPixmap>::QT_Render(int,
SDL_Rect const*, SDL_Rect const*, QPixmap*)'
Weiß da wer weiter?
Marcel schrieb:> ich versuche eine Klasse als Kind einer Singleton-Basisklasse zu> erstellen. Meine Kindklasse soll dabei wiederum als Templateklasse> ausgeführt werden. Meine Singleton-Klasse sieht wiefolgt aus:
Den Sinn dieses Singleton-Templates verstehe ich nicht. Die Besonderheit
bei einem Sigleton ist doch, daß es nur eine Instanz davon geben kann.
Wie stellt denn TSingleton das für die Klasse T sicher?
> Fehler: undefined reference to `CSurfacemanager<QPixmap>::QT_Render(int,> SDL_Rect const*, SDL_Rect const*, QPixmap*)'>> Weiß da wer weiter?
So ganz kapiere ich nicht, was du da machen willst. CSurfacemanger<T>
ist also abgeleitet von TSingleton<CSurfacemanager<T> >? Warum
eigentlich nicht von TSingleton<T>?
Prinzipiell heißt das ja, daß ein Aufruf von CSurfacemanager<T>::Get()
dir einen Zeiger auf einen CSurfacemanager<T> zurückgibt, da das T in
der Basisklasse ja einem CSurfacemanager<T> entspricht. Deshalb kommt
die Fehlermeldung des Compilers.
Rolf Magnus schrieb:> Marcel schrieb:>> ich versuche eine Klasse als Kind einer Singleton-Basisklasse zu>> erstellen. Meine Kindklasse soll dabei wiederum als Templateklasse>> ausgeführt werden. Meine Singleton-Klasse sieht wiefolgt aus:>> Den Sinn dieses Singleton-Templates verstehe ich nicht. Die Besonderheit> bei einem Sigleton ist doch, daß es nur eine Instanz davon geben kann.> Wie stellt denn TSingleton das für die Klasse T sicher?
Ausgangssituation ist folgende: Ich will den Code der
CSurfacemanager-Klasse doppelt benutzen, für 2 verschiedene Typen.
(Einmal QPixmap, einmal SDL_Texture). Beide Spezialisierungen sollen
dabei aber als Singleton-Objekt nutzbar sein.
>>> Fehler: undefined reference to `CSurfacemanager<QPixmap>::QT_Render(int,>> SDL_Rect const*, SDL_Rect const*, QPixmap*)'>>>> Weiß da wer weiter?>> So ganz kapiere ich nicht, was du da machen willst. CSurfacemanger<T>> ist also abgeleitet von TSingleton<CSurfacemanager<T> >? Warum> eigentlich nicht von TSingleton<T>?>
Weil ich es meiner Meinung, genau von diesem Typ ableiten möchte.
Dadurch stelle ich sicher, das meine beiden Singleton-Objekte auf 2
verschiedene Klassen verweisen, einmal auf CSurfacemanger<QPixmap> und
einmal auf CSurfacemanger<SDL_Texture>.
> Prinzipiell heißt das ja, daß ein Aufruf von CSurfacemanager<T>::Get()> dir einen Zeiger auf einen CSurfacemanager<T> zurückgibt, da das T in> der Basisklasse ja einem CSurfacemanager<T> entspricht. Deshalb kommt> die Fehlermeldung des Compilers.
Aber mein Aufruf ist ja CSurfacemanager<QPixmap>::Get(), dieser liefert
mir einen Zeiger auf CSurfacemanager<QPixmap> zurück und diese Klasse
sollte ein CSurfacemanager<QPixmap>::QT_Render(int, SDL_Rect const*,
SDL_Rect const*, QPixmap*) besitzen...
Die Fehlermeldung hat mMn nichts damit zu tun, dass die Basisklasse ein
TSingleton<irgendwas> ist.
Hast du etwa die Template-Klasse CSurfacemanger in eine Header-Datei und
eine CPP-Datei aufgeteilt? Und die User von CSurfacemanager inkludieren
nur die Header-Datei? Zeig mal die Definition von CSurfacemanager.
Ist das gcc? AFAIR gibts da das Problem, dass die Templates von sich aus
keinen Code erzeugen und man sie mit den tatsächlichen Typen deklarieren
(und damit implementieren) muss, wenn das nicht in .h sondern .cpp
steht.
D.h. entweder steckst du das Template in ein .h, oder du weisst schon
alle Ts deiner Templates und schreibst sie zB. ans Ende des
Singleton-cpps.
Ich hatte da auch mal einen schönen Link, der das Problem genauer
beschrieben hat (trifft nicht jeden Compiler), find ihn aber nicht mehr
:(
tictactoe schrieb:> Die Fehlermeldung hat mMn nichts damit zu tun, dass die> Basisklasse ein> TSingleton<irgendwas> ist.>> Hast du etwa die Template-Klasse CSurfacemanger in eine Header-Datei und> eine CPP-Datei aufgeteilt? Und die User von CSurfacemanager inkludieren> nur die Header-Datei? Zeig mal die Definition von CSurfacemanager.
Genau, in der Headerdatei steht lediglich die Definition der Klasse, die
deklaration von Funktionen findet in der cpp statt.
Meine Suche nach csurfacemanager.cpp in allen Projektdateien, liefert
keine Ergebnisse. Die komplette Datei findest du im Anhang.
> Ist das gcc? AFAIR gibts da das Problem, dass die Templates von sich aus> keinen Code erzeugen und man sie mit den tatsächlichen Typen deklarieren> (und damit implementieren) muss, wenn das nicht in .h sondern .cpp> steht.>> D.h. entweder steckst du das Template in ein .h, oder du weisst schon> alle Ts deiner Templates und schreibst sie zB. ans Ende des> Singleton-cpps.
Das verstehe ich nun nicht so ganz... Mein Singleton ist komplett in
einer Headerdatei implementiert, dort findet keine aufteilung statt.
Für meinen Fall werde ich wohl erstmal so hingehen und meine
Template-Klasse dadurch vereinfachen/abschaffen, das ich den konkreten
Typen durch ein typdef festlege. Da ich ohnehin nur einen Typen in einer
Umgebung benötige, kommt es letzlich aufs gleiche raus.
Würde trotzdem gerne wissen, woran es scheitert... Mein Gefühl sagt mir,
ich hab irgendwo ein Problem mit der Syntax. Rein formell, sollte
eigentlich nichts gegen die Idee/den Ansatz sprechen, den ich verfolgen
wollte...
Marcel schrieb:> Genau, in der Headerdatei steht lediglich die Definition der Klasse, die> deklaration von Funktionen findet in der cpp statt
Genau das ist der Fehler. Alle template Funktionen müssen in den Header.
Das ganze Konstrukt mit dieser Ableitung nennt sich übrigens "CRTP".
Marcel schrieb:> #define g_pSurface CSurfacemanager< QPixmap >::Get()
Warum eine hässliche, gefährliche, Textersetzung, wenn man auch ein
ordentliches typedef verwenden könnte?
>> Fehler: undefined reference to `CSurfacemanager<QPixmap>::QT_Render(int,>> SDL_Rect const*, SDL_Rect const*, QPixmap*)'
Das hat mit dem Singleton-Template nichts zu tun.
Wo hat du denn die Methode QT_Render implementiert?
In einer .hpp? Oder in eine .cpp, die nicht zum Projekt gehört?
BTW, wieso eigent QT_Render()? Sollte es, nach außen, nicht nur ein
Render() geben? Oder ist das nur die interne Implementierung für QT?
Bitte nicht ärgern. Meiner Erfahrung nach lernt man weniger durch etwas
gesagt zu bekommen, als durch mit Fragen zu Nachdenken gebracht worden
sein.
Programmierer schrieb:> Marcel schrieb:>> Genau, in der Headerdatei steht lediglich die Definition der Klasse, die>> deklaration von Funktionen findet in der cpp statt>> Genau das ist der Fehler. Alle template Funktionen müssen in den Header.> Das ganze Konstrukt mit dieser Ableitung nennt sich übrigens "CRTP".>
Cool, das wars =)
> Marcel schrieb:>> #define g_pSurface CSurfacemanager< QPixmap >::Get()> Warum eine hässliche, gefährliche, Textersetzung, wenn man auch ein> ordentliches typedef verwenden könnte?
Eigentlich berechtigter Einwand. Wie würde das denn konkret aussehen?
Ich kann mir grade mit typdef nur eine Lösung vorstellen, die mich
zwingt, das Get Manuell aufzurufen.
Bastler schrieb:>>> Fehler: undefined reference to `CSurfacemanager<QPixmap>::QT_Render(int,>>> SDL_Rect const*, SDL_Rect const*, QPixmap*)'>> Das hat mit dem Singleton-Template nichts zu tun.>> Wo hat du denn die Methode QT_Render implementiert?> In einer .hpp? Oder in eine .cpp, die nicht zum Projekt gehört?>> BTW, wieso eigent QT_Render()? Sollte es, nach außen, nicht nur ein> Render() geben? Oder ist das nur die interne Implementierung für QT?
Es gibt auch nur eine Render, QT_Render ist eigentlich intern und
privat. Nachdem es mit dieser nicht geklappt hat, hatte ich das
testweise vereinfacht. Das wird jetzt natürlich wieder zurückgebaut =)
Marcel schrieb:> Aber mein Aufruf ist ja CSurfacemanager<QPixmap>::Get(), dieser liefert> mir einen Zeiger auf CSurfacemanager<QPixmap> zurück und diese Klasse> sollte ein CSurfacemanager<QPixmap>::QT_Render(int, SDL_Rect const*,> SDL_Rect const*, QPixmap*) besitzen...
Ach so. Ich dachte, du willst eine Memberfunktion von QPixmap aufrufen,
nicht von CSurfacemanager<QPixpmap>.
Georg A. schrieb:> Ist das gcc? AFAIR gibts da das Problem, dass die Templates von sich aus> keinen Code erzeugen und man sie mit den tatsächlichen Typen deklarieren> (und damit implementieren) muss, wenn das nicht in .h sondern .cpp> steht.
Das ist kein Problem von gcc, sondern Teil von C++. Man kann das mit dem
Schlüsselwort "export" lösen, und ein Problem von gcc (und den meisten
anderen Compilern) ist, daß das nicht unterstützt wird.
Marcel schrieb:>> D.h. entweder steckst du das Template in ein .h, oder du weisst schon>> alle Ts deiner Templates und schreibst sie zB. ans Ende des>> Singleton-cpps.>> Das verstehe ich nun nicht so ganz... Mein Singleton ist komplett in> einer Headerdatei implementiert, dort findet keine aufteilung statt.
Und genau das mußt du mit allen templates machen.
> Würde trotzdem gerne wissen, woran es scheitert...
Das Template ist, wie der Name schon sagt, nur eine Vorlage für eine
Klasse. Erst dort, wo T bekannt ist, kann auch Code für die Funktionen
erzeugt werden. Dazu muß deren Quelltext aber an der Stelle bekannt
sein, was nicht der Fall ist, wenn diese in einem anderen cpp-File
definiert ist.
Programmierer schrieb:> Marcel schrieb:>> #define g_pSurface CSurfacemanager< QPixmap >::Get()> Warum eine hässliche, gefährliche, Textersetzung, wenn man auch ein> ordentliches typedef verwenden könnte?
Ein typedef für einen Funktionsaufruf? Ohne ein Makro fiele mir nur
sowas ein:
Rolf Magnus schrieb:> Man kann das mit dem Schlüsselwort "export" lösen,
Das ist seit 2011 in C++ abgeschafft...
Marcel schrieb:> Ich kann mir grade mit typdef nur eine Lösung vorstellen, die mich> zwingt, das Get Manuell aufzurufen.
Oohps, hab das ::Get übersehen.
Marcel schrieb:> Hab das jetzt mit einer WrapperFunktion gelöst. Sollte zumindest> typsicherer sein, als das define..
Ja, das ist die richtige Lösung.