Verständnisproblem: Static Variabeln
-
Danke für deine Antwort!
Am Besten mache ich mal ein Beispiel, wie ich das ganze meine:
class Vogel { public: char GetGesang() { return m_gesang; } protected: char m_gesang; }; class Spatz : public Vogel { public: static char m_gesang; }; char Spatz::m_gesang = 'G'; int main() { Spatz spatz = new Spatz(); spatz->GetGesang(); // Sollte 'G' sein return 0; }Jeder meiner Vögel hat einen anderen Gesang, der durch eine Char Variable definiert wird. Ich möchte mit spatz->Gesang() zu 'G' kommen, jedoch sollte m_gesang in Spatz statisch sein, da jeder Spatz den gleichen Gesangstyp hat...
-
Dann habe ich dich richtig verstanden und meine Antwort passte:
template<class T> class Vogel { public: char GetGesang() { return m_gesang; } static char m_gesang; }; class Spatz : public Vogel<Spatz> { }; class Taube : public Vogel<Taube> { }; template <class T> char Vogel<T>::m_gesang = '\0'; int main() { Spatz::m_gesang='G'; Taube::m_gesang='H'; Spatz spatz1,spatz2; Taube taube; cout<<spatz1.GetGesang()<<spatz2.GetGesang()<<taube.GetGesang()<<endl; // GGH return 0; }
-
SeppJ schrieb:
Dann habe ich dich richtig verstanden und meine Antwort passte:
template<class T> class Vogel { public: char GetGesang() { return m_gesang; } static char m_gesang; }; class Spatz : public Vogel<Spatz> { }; class Taube : public Vogel<Taube> { }; template <class T> char Vogel<T>::m_gesang = '\0'; int main() { Spatz::m_gesang='G'; Taube::m_gesang='H'; Spatz spatz1,spatz2; Taube taube; cout<<spatz1.GetGesang()<<spatz2.GetGesang()<<taube.GetGesang()<<endl; // GGH return 0; }Danke für deine Antwort, das funktioniert super...
Jedoch verstehe ich es nicht, könntest du bitte eine kurze Erläuterung machen? (Nur falls du Zeit hast natürlich :D)
-
Samyboy schrieb:
Jedoch verstehe ich es nicht, könntest du bitte eine kurze Erläuterung machen? (Nur falls du Zeit hast natürlich :D)
Zeit hätte ich wohl, aber kannst du genauer fragen, was du nicht verstehst? Hast du Erfahrung mit Templates?
-
SeppJ schrieb:
Samyboy schrieb:
Jedoch verstehe ich es nicht, könntest du bitte eine kurze Erläuterung machen? (Nur falls du Zeit hast natürlich :D)
Zeit hätte ich wohl, aber kannst du genauer fragen, was du nicht verstehst? Hast du Erfahrung mit Templates?
Ja, ich habe Template 1 oder 2 Mal verwendet, aber nur um zum Beispiel mehrere Typen von Argumente an eine Funktion übergeben zu können. (double, int, float etc.)
Was ich nicht verstehe ist:
Was macht das template<class T> ganz oben neben der Klasse?
Wieso sieht die Vererbung so aus: Taube : public Vogel<Taube>
Setzt diese Zeile: template <class T> char Vogel<T>::m_gesang = '\0'; alle m_gesang zu '\0'?
-
Also: Ein Template ist im wortwörtlichen Sinne eine Schablone für eine Klasse. Es ist wichtig, dass es noch keine vollständige Klasse ist. Komplett wird sie erst, wenn man sie instanziert, das heiß wenn man sie irgendwo mitsamt eines Parameters benutzt. Dann wird aus der Schablone eine Klasse für eben diesen Parameter erzeugt.
Folgendes ist die Schablone für einen Vogel:
template<class T> class Vogel { public: char GetGesang() { return m_gesang; } static char m_gesang; };Man kann nun leicht verschiedene Klassen machen:
Vogel<int> vi; Vogel<char> vc; Vogel<string> vs;Wichtig ist, das sind alles ganz verschiedene Klassen, die gar nichts miteinander zu tun haben.
Da die obige Schablone eine static Variable enthält, muss dieser bekanntlich irgendwo Speicherplatz zugewiesen werden, wie man das von static Variablen kennt:
template <class T> char Vogel<T>::m_gesang='\0';Das ist wieder eine Schablone. Wenn man das Template instanziert, dann haben die verschiedenen Instanzen für unterschiedliche Parameter nichts miteinander zu tun.
(Das setzen auf 0 ist hierbei bedeutungslos, ich wollte der Variable nur einen Anfangswert zuweisen. Kann man auch weglassen)
Gucken wir jetzt mal die abgeleiteten Klassen an:
class Spatz : public Vogel<Spatz> { }; class Taube : public Vogel<Taube> { };Diese beiden Klassen instanzieren das Vogel-Template. Da sie beide unterschiedliche Parameter für das Template verwenden, erben sie dabei von zwei ganz verschiedenen Klassen. Spatz erbt von Vogel<Spatz> und Taube erbt von Vogel<Taube>. Vogel<Spatz> und Vogel<Taube> sind wie schon gesagt, richtige Klassen die aber nicht miteinander zu tun haben. Beide enthalten aber eine static Variable 'm_gesang' die dann von Spatz und Taube geerbt wird. Und da es wie gesagt unterschiedliche Klassen sind, von denen geerbt wird, sind auch die geerbten static Variablen in Spatz und Taube verschieden (haben aber den gleichen Namen).
Warum habe ich so geerbt?:
Taube : public Vogel<Taube>Dabei geht es nur darum, dass ein einzigartiger Templateparameter zur Instanzierung von Vogel genutzt wird. Ich hätte auch folgendes machen können:
class Spatz : public Vogel<char> { }; class Taube : public Vogel<int> { };Das hätte auch funktioniert. Aber irgendwann wären mir die Namen für unterschiedliche Typen ausgegangen, darum liegt es nahe, den Klassennamen selbst als Templateparameter zu benutzen.
-
SeppJ schrieb:
Also: Ein Template ist im wortwörtlichen Sinne eine Schablone für eine Klasse. Es ist wichtig, dass es noch keine vollständige Klasse ist. Komplett wird sie erst, wenn man sie instanziert, das heiß wenn man sie irgendwo mitsamt eines Parameters benutzt. Dann wird aus der Schablone eine Klasse für eben diesen Parameter erzeugt.
Folgendes ist die Schablone für einen Vogel:
template<class T> class Vogel { public: char GetGesang() { return m_gesang; } static char m_gesang; };Man kann nun leicht verschiedene Klassen machen:
Vogel<int> vi; Vogel<char> vc; Vogel<string> vs;Wichtig ist, das sind alles ganz verschiedene Klassen, die gar nichts miteinander zu tun haben.
Da die obige Schablone eine static Variable enthält, muss dieser bekanntlich irgendwo Speicherplatz zugewiesen werden, wie man das von static Variablen kennt:
template <class T> char Vogel<T>::m_gesang='\0';Das ist wieder eine Schablone. Wenn man das Template instanziert, dann haben die verschiedenen Instanzen für unterschiedliche Parameter nichts miteinander zu tun.
(Das setzen auf 0 ist hierbei bedeutungslos, ich wollte der Variable nur einen Anfangswert zuweisen. Kann man auch weglassen)
Gucken wir jetzt mal die abgeleiteten Klassen an:
class Spatz : public Vogel<Spatz> { }; class Taube : public Vogel<Taube> { };Diese beiden Klassen instanzieren das Vogel-Template. Da sie beide unterschiedliche Parameter für das Template verwenden, erben sie dabei von zwei ganz verschiedenen Klassen. Spatz erbt von Vogel<Spatz> und Taube erbt von Vogel<Taube>. Vogel<Spatz> und Vogel<Taube> sind wie schon gesagt, richtige Klassen die aber nicht miteinander zu tun haben. Beide enthalten aber eine static Variable 'm_gesang' die dann von Spatz und Taube geerbt wird. Und da es wie gesagt unterschiedliche Klassen sind, von denen geerbt wird, sind auch die geerbten static Variablen in Spatz und Taube verschieden (haben aber den gleichen Namen).
Warum habe ich so geerbt?:
Taube : public Vogel<Taube>Dabei geht es nur darum, dass ein einzigartiger Templateparameter zur Instanzierung von Vogel genutzt wird. Ich hätte auch folgendes machen können:
class Spatz : public Vogel<char> { }; class Taube : public Vogel<int> { };Das hätte auch funktioniert. Aber irgendwann wären mir die Namen für unterschiedliche Typen ausgegangen, darum liegt es nahe, den Klassennamen selbst als Templateparameter zu benutzen.
Ich danke dir viel mal für deine Erläuterung!
Du hast mir echt viel geholfen und mich weitergebracht

Eine Frage hätte ich dann noch, sollte man das tun? Wie effizient ist das?
Denn für alle meine Unterklassen wird ja dann eine neue Basisklasse erstellt und das scheint mir ineffizient zu sein (hab aber keinen Plan von solchen Dingen)
-
Klassen sind bloß Abstrakte Gebilde. Abstraktion kostet gar nichts.
-
Dazu sollte noch gesagt werden, dass Spatz und Taube nun unterschieldiche Basisklassen haben und so nicht mehr polymorph über einen Vogel* angesprochen werden können, falls du sowas vorhattest.
-
brotbernd schrieb:
Dazu sollte noch gesagt werden, dass Spatz und Taube nun unterschieldiche Basisklassen haben und so nicht mehr polymorph über einen Vogel* angesprochen werden können, falls du sowas vorhattest.
Stimmt. Man könnte aber natürlich noch eine Klasse machen von der der Vogel erbt, dann geht das auch:
class Vogel{ public: virtual char GetGesang()=0; }; template<class T> class Hilfsklasse: public Vogel { public: static char m_gesang; virtual char GetGesang(){return m_gesang;} }; class Spatz : public Hilfsklasse<Spatz> { }; class Taube : public Hilfsklasse<Taube> { }; template <class T> char Hilfsklasse<T>::m_gesang='\0'; int main() { Spatz::m_gesang='G'; Taube::m_gesang='H'; Vogel *voegel[2]; voegel[0]=new Spatz(); voegel[1]=new Taube(); cout<<voegel[0]->GetGesang()<<voegel[1]->GetGesang()<<endl; // GH return 0; }