Frage zu Klassentemplates
-
Ich wünsche einen schönen guten Morgen.
Ich benötige Hilfe zu Klassentemplates, da mich die Syntax etwas verwirrt und ich in den gängigen Hilfen zwar viele Beispiele, doch nicht meine Problemstellung finde.
Zu der Frage:
Ich habe eine Template-Klasse, die wie folgt aussieht:
template <class VergleichbaresObjekt* obj> class TemplateListe { public: ~TemplateListe() { delete liste;}; TemplateListe() { liste = new TList(); }; void elementHinzufuegen(VergleichbaresObjekt* obj) { liste->Add(element); }; void elementLoeschen(VergleichbaresObjekt* obj) { liste->Remove(element); }; void elementLoeschen(int pos) { liste->Delete(pos); }; VergleichbaresObjekt* elementHolen(int pos); private: TList* liste; }; template <class VergleichbaresObjekt* obj> VergleichbaresObjekt* TemplateListe<obj>::elementHolen(int pos) { for (int i=0; i<liste->Count; i++) { if (((VergleichbaresObjekt*)(liste->operator[](i)))->getID() == pos) { return (VergleichbaresObjekt*) liste->operator[](i); } } return NULL; }Diese Klasse soll eine Liste darstellen, in die alle Objekte eingefügt werden können, die von VergleichbaresObjekt erben. Dies brauche ich, damit ich den Operator== mit VergleichbaresObjekt und int-Wert überschreiben kann.
Wenn ich dies so schreibe, erhalte ich jedoch einen Kompilier-Fehler bei folgendem Aufruf:
TemplateListe<IrgendEinObjekt>* liste; // Fehlermeldung: Ungültige Template- ArgumentlisteDie Klasse IrgendEinObjekt ist so definiert:
#include <System.hpp> #include "VergleichbaresObjekt.h" class IrgendEinObjekt: public VergleichbaresObjekt { private: AnsiString name; public: AnsiString getName() { return name; }; };und zu guter letzt noch die Klasse VergleichbaresObjekt zur Vollständigkeit:
class VergleichbaresObjekt { private: int id; protected: public: bool operator == (int wert); int getID() { return id; }; };Ich bitte um Hilfe. Ich versuche damit in die Thematik der KlassenTemplates einen Einblick zu erhalten, verstehe jedoch nicht, warum dies nicht geht. Wenn mir dies einer von euch beantworten könnte wäre ich sehr dankbar.
Oliver.
-
Hallo nochmals,
da bisher noch keine Antwort kam...
Habe ich mich so dämlich ausgedrückt?
- Wenn ja, bitte ich dies zu entschuldigen.Vielleicht kann mir ja doch noch jemand helfen.
Das wäre super.Oliver.
-
Vertausch mal * und >.
-
Wenn du im Aufruf meinst, habe ich das hiermit getan, allerdings änderte sich an der Fehlermeldung nichts.
Sprich:
Vorher:
TemplateListe<IrgendEinObjekt>* liste;Nachher:
TemplateListe<IrgendEinObjekt*> liste;Oder habe ich deinen Tipp missinterpretiert?
Danke trotzdem.
Oliver
-
Hallo
Sieh dir nochmal die Grundlagen der der templateprogrammierung an
template <class VergleichbaresObjekt> class TemplateListe ...bis bald
akari
-
...ich bekomme die Grundlagen schon hin, dazu gibt es ja genug Hilfen.
Vielleicht habe ich die Frage doch schlecht formuliert. Ich versuche es also - wenn gestattet - noch einmal.
Ein generelles Klassentemplate habe ich so geschrieben:
template <class T> class Liste { public: ~Liste() { delete liste;}; Liste() { liste = new TList(); }; void elementHinzufuegen(T* element) { liste->Add(element); }; void elementLoeschen(T* element) { liste->Remove(element); }; void elementLoeschen(int pos) { liste->Delete(pos); }; int anzahlElementeHolen() { return liste->Count; }; T* elementHolen(int pos); private: TList* liste; }; template <class T> T* Liste<T>::elementHolen(int pos) { //mache irgendwas; }Soweit sogut.
Mein Problem ist, dass ich für Class T irgendeine Klasse setzen kann. Ich würde diese Vielfalt jedoch gerne auf eine bestimmte Gruppe eingrenzen. Es soll eine Klasse sein, die von einem bestimmten Objekt (in meinem Fall VergleichbaresObjekt) erbt.
Dazu finde ich keine "Grundlagen", da dort immer wieder von "Spezialisierungen" die Rede ist, ich dies aber entweder nicht nachvollziehen und/oder ausführen kann, oder aber es nicht meinem Problem entspricht.
Vielleicht fehlen mir tatsächlich Grundlagen, ich denke jedoch, dass ich mit einer schnellen, einfachen und unkomplizierten Hilfe an dieser Stelle besser bedient bin.
Ich bitte also nochmals um eine konstruktive Hilfe an dieser Stelle.
Oliver.
P.S.: Wenn ich nämlich Akaris "Beispiel" richtig deute, würde ich so irgendeine Klasse erlauben, die den Namen "VergleichbaresObjekt" erhält. Das will ich aber nicht. Deshalb nochmals dieser Post. Sollte ich mich so verquer ausgedrückt haben, entschuldige ich mich dafür.
-
Hallo
...ich bekomme die Grundlagen schon hin, dazu gibt es ja genug Hilfen.
Offenbar nicht. Der Fehler auf den ich hingewiesen habe und den du klammheimlich korrigiert hast deutet auf Lücken in den Grundlagen hin.
Mein Problem ist, dass ich für Class T irgendeine Klasse setzen kann. Ich würde diese Vielfalt jedoch gerne auf eine bestimmte Gruppe eingrenzen. Es soll eine Klasse sein, die von einem bestimmten Objekt (in meinem Fall VergleichbaresObjekt) erbt.
Das geht im aktuellen C++ Standard nicht. Du must also darauf vertrauen das der Anwender weiß wann das Template einzusetzen ist und wann nicht.
bis bald
akari
-
Dieser Thread wurde von Moderator/in akari aus dem Forum VCL/CLX (Borland C++ Builder) in das Forum C++ verschoben.
Im Zweifelsfall bitte auch folgende Hinweise beachten:
C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?Dieses Posting wurde automatisch erzeugt.
-
Okay,
bisher dachte ich nicht, dass man sich rechtfertigen muss, wenn man hier eine Frage stellt, doch man lernt nie aus!
"Klammheimlich korrigiert" habe ich eigentlich nichts. Ich wollte - wie auch gesagt - nur zeigen, dass ich mit einem standardmäßigen Template, wie es die von mir ebenfalls angesprochenen Hilfen zeigen, angefangen habe, dieses jedoch dann spezialisieren wollte.
Dass das nicht geht, ist die Information, die mir fehlte. Nenne es Lücken oder Unkenntnis, ich finde nur schade, dass man wegen so etwas direkt - nennen wir es geschönt - belehrt wird.
Wenn ich der ultimative Programmierkönig wäre, würde ich hier nichts lernen wollen. Nur aus Tutorials und Büchern kann nicht jeder Mensch lernen. Dass solltest du wissen. Wenn das bei dir und manchen anderen der Fall ist, herzlichen Glückwunsch. Es ist nicht die Regel. Ich habe nie vor wie andere ein fertiges Programm zu erhalten. Ich wollte lediglich einen guten Tipp. Als guten Tipp bezeichne ich nicht "fange nochmal bei den Grundlagen an...". Ich in meinem beschränkten Verstand halte nämlich die Template-Programmierung nicht für Anfängerkram.
So, komme ich nun zu meinem Schlussplädoyer:
Ich finde es kontraproduktiv solche Sätze zu hören. Wenn es also so aussieht, habe ich für mich gelernt, dass hier wohl der falsche Ort ist, um meine Fragen zu stellen. Wenn ich mich Spott aussetzen will, setze ich mir eine rote Nase auf und laufe gackernd über einen Marktplatz.
Für alle die, die sich jetzt vielleicht im Irrglauben befinden, ich versuche zu drohen, dieser Community meine Anfängerfragen zu entziehen - falsch! Nochmals lesen. Ich bitte lediglich darum, dass auf ernst gemeinte Fragen für lernwillige Leute ein wenig besser eingegangen wird als in einer solch beleidigenden Weise wie "klammheimlich korrigiert um ..."....Und jetzt bin ich auf eine Antwort gespannt.
In froher Erwartung, Oliver.
-
Wenn du deine Fragen immer so stellst wie du diese gestellt hast, dann ist dies hier das falsche Forum. Allerdings bin ich nicht sicher ob du ein "richtiges" finden wirst, da es kaum irgendwo Leute gibt die hellsichtig sind oder gerne raten.
Ok, zum Thema.
Es gibt 2 Möglichkeiten wie du dein "Problem" lösen kannst:-
Verwende kein Template, sondern einfach nur eine Klasse die mit "VergleichbaresElement*" arbeitet. Natürlich musst du "ausserhalb" dann immer casten.
-
Schreib dein Template ganz normal generisch, und konvertiere den Zeiger implizit (also ohne cast) in einen "VergleichbaresElement*":
class Comparable { // ... }; template <class T> class Foo { public: void Insert(T* p) { Comparable* c = p; // <-- impliziter Typkonvertierung hier, m_list->push_back(c); } T* GetFirst() const { Comparable* c = m_list->front(); return static_cast<T*>(c); // <-- hier musst du explizit casten, was aber sicher ist // solange du sicherstellst dass immer nur T* eingefügt werden können } // ... };Angenommen du hast Version 1) schon, dann ist Version 2 trivial:
class Comparable { // ... }; class FooComparable { public: void Insert(Comparable* p); Comparable* GetFirst() const; // ... }; template <class T> class Foo { public: void Insert(T* p) { m_fooComparable.Insert(p); // <-- hier wieder implizit } T* GetFirst() const { return static_cast<T*>(m_fooComparable.GetFirst()); // <-- hier wieder explizit } // ... private: FooComparable m_fooComparable; };Dadurch stellst du zwar nicht sicher dass die Klasse Foo<Bar> nicht instanziert werden kann wenn Bar* nicht implizit in Comparable* konvertierbar ist, aber sie kann nicht effektiv verwendet werden, da z.B. Foo::Insert nicht instanzierbar ist. Anders gesagt: "Foo<Bar>* p = new Foo<Bar>()" würde noch compilieren, ein darauffolgendes "p->Insert(new Bar())" allerdings nichtmehr.
p.S.: Möglichkeit 3: du kannst BOOST_STATIC_ASSERT und boost::is_base_and_derived verwenden:
class Comparable { // ... }; template <class T> class Foo { BOOST_STATIC_ASSERT((boost::is_base_and_derived<Comparable,T>::value)); // ... };Damit stellst du allerdings nicht sicher dass bei einem Aufruf über einen "T*" auch wirklich die Funktion aus "Comparable" aufgerufen wird:
class Foo { public: virtual void f(int i) = 0; }; class Bar : public Foo { public: void f(int i) { printf("1"); } }; class Baz : public Bar { public: void f(int i, int j = 1) { printf("2"); } }; int main() { Baz b; b.f(1); // gibt "2" aus static_cast<Foo*>(&b)->f(1); // gibt "1" aus }Du solltest also wenn du sicher die Funktionen aus "Comparable" verwenden willst trotz dem "static assert" auf "Comparable*" casten, und dann über den "Comparable*" die gewünschte Funktion aufrufen.
p.p.S.: man kann auch eine Spezialisierung für den Fall "ist von Blubb abgelietet" machen, allerdings nur über einen Trick der SFINAE ausnutzt. Dazu müsstest du z.B. boost::is_base_and_derived mit boost::enable_if kombinieren. Wenns dich interessiert, lies das:
http://www.boost.org/libs/utility/enable_if.html
p.p.p.S.: Kommentare ala "wenn ich mich zum Gespött machen möchte..." kommen erfahrungsgemäss häufig von Leuten die sich schlecht ausdrücken. Das führt nämlich dazu dass sie falsch verstanden werden, und das wiederum dazu dass blöde Meldungen kommen. Sogesehen kannst du also die Häufigkeit von blöden Meldungen dadruch selbst regulieren indem du dich mehr oder weniger gut & genau ausdrückst.
-
-
ich danke dir für diese ausführliche und hilfreiche Antwort.
Ein paar Dinge sind mir zwar noch nicht klar, doch ich denke, ich komme damit weiter.Dass meine Frage schief formuliert war, habe ich ja selber gemerkt. Passt schon.
Das "Gespött" jedoch bezog sich auf die Art und Weise der Reaktion, die ziemlich - in meinen Augen - unpassend war.
Für mich ist die Sache hiermit gegessen. Danke nochmals.
Oliver.