Templates: Linkerproblem mit aufzurufender Methode in Basis-Templateklasse
-
Hallo,
ich habe folgendes Klassentemplate für eine QList:
template <class T> class dList : public QList<T*> { public: dList(T* t) { QList<T*>::append(t); } int qSort(int comp_(T*,T*,void *),void *data=NULL){ return qSort(this,comp_,data); } int qSort(dList<T> *iList,int comp_(T*,T*,void *),void *data = NULL); };Um mir den Aufruf der qSort-Methode zu vereinfachen, ist die Methode im Template oben überschrieben.
Die qSort-Methode habe ich auch in der gleichen Header-Datei definiert, damit der Linker das nicht anmeckert:template <class T> int qSort(dList<T> *iList,int comp_(T*,T*,void *),void *data){ .... return 1; }Jetzt habe ich eine abgeleitete Templateklasse, die das Klassentemplate spezialisiert:
class ArrDlist: public dList<DNode>{ public: ArrDlist(); };Wenn ich jetzt versuche, die qSort-Methode mit der Vergleichsfunktion aufzurufen, macht der Linker allerdings Probleme:
int compNode(DNode* a, DNode* b, void *) { return 0; } ArrDlist::ArrDlist(): dList<DNode>(){ dList<DNode>::qSort(compNode); } int main(int argc, char *argv[]) { ArrDlist* array = new ArrDlist(); }Der Linker-Fehler:
main.obj
Fehler:LNK2019: Verweis auf nicht aufgelöstes externes Symbol ""public: int __thiscall dList<class DNode>::qSort(class dList<class DNode> ,int (__cdecl)(class DNode *,class DNode *,void *),void *)" (?qSort@?dList@VDNode@@@@QAEHP6AHPAVDNode@@0PAX@Z1@Z)".Allerdings ist meinerserachtens der Aufruf korrekt und die Parameter stimmen auch, die der Linker aufführt. Woran könnte es noch liegen?
Vielen Dank für eure Hilfe.
Gruß,
Tobias
-
Dies:
template <class T> int qSort(dList<T> *iList,int comp_(T*,T*,void *),void *data);ist eine völlig andere Funktion als
template <class T> class dList : public QList<T*> { int qSort(dList<T> *iList,int comp_(T*,T*,void *),void *data = NULL); };Das eine ist eine Memberfunktion von dList, das andere eine freie Funktion.
Allgemein: Schrecklicher Code. Wie kannst du einerseits Templates kennen und andererseits so viel mit Zeigern, noch dazu void-Zeigern, rumpfuschen? Die Templates ermöglichen dir doch gerade, dass es sehr einfach ist, keine void* verwenden zu müssen! Und die ganzen normalen Zeiger und dynamischen Speicheranforderungen kann ich überhaupt nicht nachvollziehen.
Und wieso nutzt du nicht die Standardbibliothek? Das ganze Programm wären zwei Zeilen:
#include <container_deiner_wahl> // Wieso eigentlich eine List? #include <algorithm>Ungarische Notation ist in C++ auch out, dein Programm ist ein Paradebeispiel dafür, warum.
-
Hallo,
vielen Dank für die Anmerkungen. Das war sehr hilfreich.
Das mit der void*-Zeigern ist nicht schön, da hast Du recht. Das werde ich ändern.
Ich bin dabei, den nicht von mir geschriebenen Code von einem Riesenmakro in ein Template umzuwandeln.Diese Zwischenschicht ist allerdings nötig, da dies eine Basisklasse für viele andere Funktionen ist. Daher würde mir wahrscheinlich ein STL-Container nicht viel nützen, da ich auch die ganzen Aufrufen anpassen müsste. Oder gibt es da einen anderen Weg?
Gruß,
Tobias
-
Sir_Tobias schrieb:
Diese Zwischenschicht ist allerdings nötig, da dies eine Basisklasse für viele andere Funktionen ist. Daher würde mir wahrscheinlich ein STL-Container nicht viel nützen, da ich auch die ganzen Aufrufen anpassen müsste. Oder gibt es da einen anderen Weg?
Du könntest einen kleinen Wrapper drumrum schreiben. Oder du machst dir eben einmal die Mühe, alle Aufrufe so anzupassen, dass sie mit allen möglichen Objekten klarkommen (d.h. Templates und Iteratoren wie in der Standardbibliothek).
Mach dir auch unbedingt auch mal Gedanken, ob die ganze Zeigerei (nicht nur void*) wirklich nötig ist. Höchstwahrscheinlich nicht. Dann wäre es bloß unnötig umständlich, fehleranfällig und langsam. Falls es doch nötig sein sollte, dann nimm wenigstens Smartpointer, dann passieren dir nicht solche Fehler wie in deiner main. Und für call-by-reference nimm bitte Referenzen! Die sind genau dafür da, wie der Name schon sagt.