Funktion wird in Basisklasse nicht gefunden
-
Hi, warum zum Henker findet der Compiler die Length Funktion aus der Basisklasse "ClassA" im "operator=" nicht? Erst wenn man der Funktion die Basisklasse davorschreibt (ClassA<T>::Length(N)) kann der Compiler diese zuordnen. Dabei hängt die Funktion Length nicht mal vom Templateargument ab. Das kann doch nicht wahr sein. Langsam muss man C++ wirklich als kaputt bezeichnen. Eine Schande was aus dieser Sprache geworden ist. Alles mit unnützen (und halbgaren dazu) Features aufblähen, aber absolute Basics gehen nicht ohne völlig unnötigen code bload...
template <class T> class ClassA { public: ClassA() : _length(0) { }; ClassA(size_t length) : _length(length) { }; size_t Length() const { return _length; }; void Length(size_t length) { _length = length; }; private: size_t _length; }; template <class T> class ClassB : public ClassA<T> { public: ClassB() { }; template <size_t N> ClassB(const T (&value)[N]) : ClassA<T>(N) { } template <size_t N> ClassB<T>& operator=(const T (&value)[N]) { ClassA<T>::Length(N); return *this; } }; int main() { ClassB<char> test = "Test"; return 0; }
-
Welchen Compiler nutzt du? Denn beim gcc geht es: Ideone-Code
Oder hast du
#include <cstdlib>
(oder#include <cstddef>
) vergessen (wegensize_t
)?
-
Also mit GCC 7.3 kommt der Fehler auch. Fehler lautet:
main.cpp:53:9: error: there are no arguments to ‘Length’ that depend on a template parameter, so a declaration of ‘Length’ must be available [-fpermissive] Length(10); ^~~~~~ main.cpp:53:9: note: (if you use ‘-fpermissive’, G++ will accept your code, but allowing the use of an undeclared name is deprecated)
Hab dazu das hier gefunden, bin es aber selber noch am lesen und verstehen: https://stackoverflow.com/a/4643295
Ein möglicher Workaround ist jedenfalls mit
this->
zu qualifizieren. Wäre immerhin etwas kürzer.
-
Wenn deine Basisklasse eine Template-Klasse ist musst du Member immer mit
this
oder dem Scope-Operator qualifizieren. Das ist so aber ich weiß nicht warum. Jedenfalls find ich das auch nervig.
-
ClassA<T> hängt ganz offensichtlich vom Templateparameter T ab, und wird deshalb beim unqualifizierten Lookup nicht durchsucht (2-phase lookup). Um ein Durchsuchen per ADL zu erreichen, muss der Ausdruck Length so verändert werden, dass klar ist, dass dieser Ausdruck ebenfalls vom Templateargument abhängt (typischerweise durch this->Length), oder aber man arbeitet direkt mit einem qualifizierten Bezeichner. Der Klassenbezeichner muss nicht unbedingt die Basisklasse bezeichnen, es genügt, wenn klar ist, dass ein (ggf. geerbetes) Klassenmember gemeint ist (also z.B. ClassA<T>::Length , ClassB<T>::Length, ClassB::Length in diesem Fall).
@Enumerator sagte in Funktion wird in Basisklasse nicht gefunden:
Das kann doch nicht wahr sein. Langsam muss man C++ wirklich als kaputt bezeichnen. Eine Schande was aus dieser Sprache geworden ist. Alles mit unnützen (und halbgaren dazu) Features aufblähen, aber absolute Basics gehen nicht ohne völlig unnötigen code bload...
Das beschriebene Verhalten besteht seit 20 Jahren so (-die Anzahl der Jahre, bis alle Compiler konform waren). Also genug Zeit, sich dieses Wissen anzueignen.
-
@Enumerator
Der Grund warumLength
ohne Weiteres nicht gefunden wird, ist, dass es alle möglichen Spezialisierungen vonClassA
geben könnte, die alle möglichen Funktionen definieren. Spezialisierungen müssen ja nicht dem Haupt-Template ähnlich sein. Und vor allem werden Spezialisierungen auch manchmal von anderen Entwicklern geschrieben als das Haupt-Template.Die Regel existiert nun um Überaschungen und Fehler zu vermeiden.
Angenommen du verwendest in
ClassB
jetzt eine bestimmte freie Funktion. Und angenommen in irgend einer Spazialisierung vonClassA<T>
wird dann eine Memberfunktion des selben Namens definiert. Dann würde ohne diese Regel je nach Template-Parameter die freie Funktion oder eben die Memberfunktion vonClassA<T>
verwendet. Weiters würde, falls die Funktion gar nicht existiert, die Fehlermeldung so lange verzögert bis wirklich das TemplateClassB
mit einem konkreten Typ instanziert wird.Beides ist nicht wünschenswert, und die Regel verhindert beides. Und wie @camper schon geschrieben hat, gibt es diese Regel seit C++98. Bloss dass bestimmte Compiler recht lange gebraucht haben um sie umzusetzen - Visual C++ z.B. war da IIRC recht spät dran.
-
@Dravere sagte in Funktion wird in Basisklasse nicht gefunden:
Ein möglicher Workaround ist jedenfalls mit this-> zu qualifizieren. Wäre immerhin etwas kürzer.
Ich würde
this->Foo
in den meisten Fällen vorziehen, auf Grund der Unterschiede zuClassA<T>::Foo
:- Bei
this->Foo
bleibt ein evtl. virtueller Funktionsaufruf virtuell - Bei
this->Foo
wirdFoo
nicht aufClassA<T>::Foo
festgenagelt, was einen Unterschied machen kann sobald man eine weitere Basisklasse zwischenClassB
undClassA
einfügt
In beiden Fällen ist IMO öfter das Verhalten von
this->Foo
erwünscht als das Verhalten vonClassA<T>::Foo
.
- Bei