Nicht-Templateklasse mit Template-Basisklasse -> Konstruktor in Quelltextdatei
-
Hallo,
ich habe folgendes Basisklasse:
template<class container_type> class Data { //... };Nun leite ich mir davon eine Klasse Image ab:
class Image : Data<std::vector<Triple<int,int,int> > >(Triple ist eine selbstgeschriebene Klasse, die nichts anderes macht als std::pair, bloß halt mit drei Werten statt zwei)
Eigentlich kann ich jetzt davon ausgehen, dass die Klasse Image kein Template ist.
Zum Verständnis noch vor dem Problem folgendes (Member von Image):
public: enum Colorspace { CS_RGB, CS_YCrCb }; //... typedef std::vector<Triple<int,int,int> > ImageVector;Außerdem befindet sich alles im Namespace Container.
Das alles steht in der Headerdatei. Problem: Ich möchte die Konstruktoren der Klasse Image, wie für Nicht-Templates üblich, in die CPP-Datei schreiben.
Also sage ich im Header:
Image(const ImageVector& image,int height,int width,Colorspace colorspace); Image(const std::vector<ImageVector>& image,Colorspace colorspace);(mglw. liegt hier schon der Fehler?)
Quelltextdatei:
Container::Image::Image(const Container::Image::ImageVector& image,int height,int width,Container::Image::Colorspace colorspace) : Data<ImageVector>(image), width(width), height(height), colorspace(colorspace) { }-> und da ist der Fehler.
bcc32 meldet in der Zeile ab dem ":" (Initialisierung)
[C++ Fehler] data.cpp(17): E2038 Deklaration oder Definition von 'Container::Image::Image(const std::vector<Triple<int,int,int> blabla > &,int,int,Container::Image::Colorspace)' hier nicht zulässigDer entsprechende "Basis"-Konstruktor
Data(const container_type& content) : content(content) { }ist vorhanden.
Wie kann ich dieses Problem lösen?
Vielen Dank schon einmal,
MfG Lars
-
Der Fehlermeldung nach würd ich sagen, du hast irgendwo ein Semikolon oder eine Klammer vergessen.
-
Header:
//... #include "util.h" namespace Shannon { namespace Container { template<class container_type> class Data { protected: container_type content; public: Data(const container_type& content) : content(content) { } virtual container_type& getText() = 0; virtual const container_type& getText() const = 0; virtual Data& setText(const container_type& newContent) = 0; }; template<class Ch,class Tr=std::char_traits<Ch>,class A=std::allocator<Ch> > class Text : public Data<std::basic_string<Ch,Tr,A> > { protected: typedef std::basic_string<Ch,Tr,A> string_type; public: Text(const string_type& content) : Data(content) { }; string_type& getText() { return content; } const string_type& getText() const { return content; } Text& setText(const string_type& newContent) { Data::content = newContent; return this; } }; class Image : public Data<std::vector<Triple<int,int,int> > > { public: enum Colorspace { CS_RGB, CS_YCrCb }; private: int height,width; protected: typedef std::vector<Triple<int,int,int> > ImageVector; Colorspace colorspace; public: Image(const ImageVector& image,int height,int width,Colorspace colorspace); Image(const std::vector<ImageVector>& image,Colorspace colorspace); }; } } #endifQuelltext:
namespace Shannon { Container::Image::Image(const Container::Image::ImageVector& image,int height,int width,Container::Image::Colorspace colorspace) : Data<ImageVector>(image), width(width), height(height), colorspace(colorspace) { } Container::Image::Image(const std::vector<Container::Image::ImageVector>& image,Colorspace colorspace) : Data<ImageVector>(ImageVector()), colorspace(colorspace), width(0), height(0) { } } // End NamespaceJetzt habe ich das mal in den g++ gesteckt:
In file included from D:\Eigene Dateien\Projekte & data.cpp:6: data.h: In constructor `Shannon::Container::Text<Ch, Tr, A>::Text(const std::basic_string<_CharT, _Traits, _Alloc>&)': data.h:39: error: class `Shannon::Container::Text<Ch, Tr, A>' does not have any field named `Data' data.h: In member function `std::basic_string<_CharT, _Traits, _Alloc>& Shannon::Container::Text<Ch, Tr, A>::getText()': data.h:43: error: `content' undeclared (first use this function) data.h: In member function `const std::basic_string<_CharT, _Traits, _Alloc>& Shannon::Container::Text<Ch, Tr, A>::getText() const': data.h:48: error: `content' undeclared (first use this function) data.h: In member function `Shannon::Container::Text<Ch, Tr, A>& Shannon::Container::Text<Ch, Tr, A>::setText(const std::basic_string<_CharT, _Traits, _Alloc>&)': data.h:53: error: `content' undeclared (first use this function)Jetzt bin ich total konfus... Eine abgeleitete Klasse erhält doch Zugriff auf die Member der Basisklasse. Die Basisklasse enthält content, also darf ich doch drauf zugreifen, oder?
Und der Aufruf des Konstruktors einer Basisklasse wird doch auch so gemacht, wie ich es geschrieben habe, oder nicht?
-
Hallo,
ich sehe spontan zwei Fehler: Einmal fehlen dir die Template-Argumentlisten. Z.B. hier:Text(const string_type& content) : Data(content) { };Richtig wäre:
Text(const string_type& content) : Data<std::basic_string<Ch,Tr,A> >(content) { }Besser:
template<class Ch,class Tr=std::char_traits<Ch>,class A=std::allocator<Ch> > class Text : public Data<std::basic_string<Ch,Tr,A> > { protected: typedef std::basic_string<Ch,Tr,A> string_type; typedef Data<std::basic_string<Ch,Tr,A> > base; public: Text(const string_type& content) : base(content) { } ...Außerdem musst du Namen aus abhängigen Basisklassen qualifizieren, da sie sonst nicht gefunden werden (-> Suchfunktion):
Statt:
string_type& getText() { return content; }string_type& getText() { return this->content; }setText muss zu:
Text& setText(const string_type& newContent) { base::content = newContent; // oder // this->content = newContent; return this; }werden.
-
Danke, das behebt schon mal einiges. Jetzt ist aber immer noch das alte Problem:
Container::Image::Image(const Container::Image::ImageVector& image,int height,int width,Container::Image::Colorspace colorspace) : base(image), width(width), height(height), colorspace(colorspace) { }Das habe ich jetzt in der Quelltextdatei verändert. Aber die Fehlermeldung, dass die Definition nicht zulässig sei, kommt immer noch. Muss ich das etwa in den Header schreiben?
-
Merkwürdig ist ja, dass g++ nichts mehr zu meckern hat, der bcc32 aber sehr wohl...
-
Ich kann hier nichts falsches mehr entdecken. Ich vermute, dass bcc sich daran stört, dass sich die Definition nicht im die Klassendefinition unmittelbar umschließenden Namensraum befindet. Der Standard ist hier eindeutig und lässt das zu. Also ist das möglicherweise ein Compilerbug. Selbst der Comeau-online Compiler hat hier keine Probleme. Übrigens kannst du bei der Definition auf die Verwendung qualifizierter Namen für die Argumenttypen verzichten, denn der entsprechende Namensraum ist bereits durch die Nennung der Funktion selbst bestimmt. es genügt also:
Shannon::Container::Image::Image(const ImageVector& image,int height,int width,Colorspace colorspace) : Data<ImageVector>(image), width(width), height(height), colorspace(colorspace) { }
-
Man mag es nicht glauben, aber in deiner Variante nimmt es der bcc! Oh mann, ist das blöd. Darauf soll man nun kommen... Mein Problem war jetzt, dass ich das eigentlich für zu lang halte: Shannon::Data::Image::Image usw. usf. Weil ich in Bibliotheken gerne ein Namespace mit dem Bibliotheksnamen und dann thematische Sub-Namespaces benutze, schreibe ich in die Quelltextdateien halt um die Funktionen schnell die NS-Definition drumrum. Aber wenns ihn stört, dann halt so.