Templat in Klasse



  • Mh also so?

    #ifndef VECTOR_HPP_INCLUDED
    #define VECTOR_HPP_INCLUDED
    
    template <class T>
    class vector
    {
        public:
        vector(int size);
        ~vector();
    
        private:
        T *m_data;
        int m_size;
    };
    
    template <class T>
    vector::vector(int size)
    :m_size(size)
    {
        m_data=new T[m_size];
    }
    
    template <class T>
    vector::~vector()
    {
        delete []m_data;
    }
    
    #endif // VECTOR_HPP_INCLUDED
    

    Aber och gottchen da is ja au wieder derbst viel falsch:

    -------------- Build: Debug in Telefonbuch ---------------
    Compiling: vector.cpp
    In file included from vector.cpp:1:
    vector.hpp:19: error: template<class T> class vector' used without template parameters vector.hpp:20: error: ISO C++ forbids declaration ofvector' with no type
    vector.hpp:20: error: declaration of template template<class T> int vector(int)' vector.hpp:6: error: conflicts with previous declarationtemplate<class T> class vector'
    vector.hpp:6: error: previous non-function declaration template<class T> class vector' vector.hpp:20: error: conflicts with function declarationtemplate<class T> int vector(int)'
    vector.hpp: In function int vector(int)': vector.hpp:20: error: only constructors take base initializers vector.hpp:22: error:m_data' undeclared (first use this function)
    vector.hpp:22: error: (Each undeclared identifier is reported only once for each function it appears in.)
    vector.hpp:22: error: m_size' undeclared (first use this function) vector.hpp:23: warning: no return statement in function returning non-void vector.hpp: At global scope: vector.hpp:27: error: expected constructor, destructor, or type conversion before '::' token vector.hpp:27: error: expected;' before '::' token
    vector.cpp:3: error: template<class T> class vector' used without template parameters vector.cpp:4: error: ISO C++ forbids declaration ofvector' with no type
    vector.cpp: In function int vector(int)': vector.cpp:4: error:int vector(int)' redeclared as different kind of symbol
    vector.hpp:6: error: previous declaration of template<class T> class vector' vector.hpp:6: error: previous non-function declarationtemplate<class T> class vector'
    vector.cpp:4: error: conflicts with function declaration int vector(int)' vector.cpp:4: error: only constructors take base initializers vector.cpp:6: error:m_data' undeclared (first use this function)
    vector.cpp:6: error: T' has not been declared vector.cpp:6: error:m_size' undeclared (first use this function)
    vector.cpp: At global scope:
    vector.cpp:9: error: expected constructor, destructor, or type conversion before '::' token
    vector.cpp:9: error: expected ,' or;' before '::' token
    Process terminated with status 1 (0 minutes, 0 seconds)
    24 errors, 1 warnings

    EDIT: !!!!!
    Es geht jetzt irgendwie doch, der hat noch die alte ".cpp" geladen.
    Aber die eine Frage wäre trotzdem noch offen, ist das nicht hässlich alles in eine .hpp zu schreiben, bzw. is das n guter Stil, wie macht ihr das?

    EDIT2:
    Mh irgendwie gehts jetzt doch nicht!!! Ich blicks net 😞

    Und irgendwie is des doch hässlich alles in eine ".hpp" reinzuschreiben?
    Dankeschön schon mal im Voraus.



  • es muss eher heissen:

    template<class T>
    vector<T>::vector(){//...
    

    weil die klasse "vector" gibts gar nicht, es gibt nur template "vector<T>"

    edit: guter stil? hehe, such mal die include-dateien auf, und schau dir zB die ganzen dinger wie "MAP" oder "LIST" an, also die STL-container (so ein typischer beispiel für templates) Das ist guter stil! ich glaube ich bin nicht der einzige, der da nicht durchblickt^^ 😃



  • So jetzt kommt bei meinem Code noch ein komischer Fehler, den verstehe ich net:

    -------------- Build: Debug in Telefonbuch ---------------
    Compiling: main.cpp
    Linking console executable: .\Telefonbuch.exe
    obj\Debug\main.o: In function ZN6vectorISsED1Ev': C:/MinGW/Andi/C++/Projekte/Telefonbuch/vector.hpp:(.text$\_ZN6vectorISsEC1Ei[vector<std::basic\_string<char, std::char_traits<char>, std::allocator<char> > >::vector(int)]+0x43): undefined reference tosizestd::string::size()'
    obj\Debug\main.o: In function main': C:/MinGW/Andi/C++/Projekte/Telefonbuch/main.cpp:8: undefined reference tosizestd::string::~size()' !!! <-- HIER !!!
    obj\Debug\main.o: In function ZN6vectorISsED1Ev': C:/MinGW/Andi/C++/Projekte/Telefonbuch/vector.hpp:(.text$\_ZN6vectorISsED1Ev[vector<std::basic\_string<char, std::char_traits<char>, std::allocator<char> > >::~vector()]+0xa9): undefined reference tosizestd::string::~size()'
    C:/MinGW/Andi/C++/Projekte/Telefonbuch/vector.hpp:(.text$_ZN6vectorISsED1Ev[vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::~vector()]+0xd3): undefined reference to `sizestd::string::~size()'
    collect2: ld returned 1 exit status
    Process terminated with status 1 (0 minutes, 0 seconds)
    1 errors, 0 warnings

    HÄÄÄ? Warum undefined reference to `sizestd::string::~size()???
    Und was hat das mit dem Destruktor zu tun??? Der is doch vortual!!?? 😞

    Ich poste einfach mal den Code:

    main.cpp

    #include <iostream>
    #include "vector.hpp"
    using namespace std;
    
    int main()
    {
    	cout << "   MEN\x9a \n";
    	cout << "''''''''''''''''''\n\n";
    	cout << "[1] Name Suchen\n";
    	cout << "[2] Neuer Name\n";
    	vector<string> data_base(20);
    	data_base[7]="1435";
    	cout << data_base[7] << "\n";
    
    	return 0;
    }
    

    vector.hpp

    #ifndef VECTOR_HPP_INCLUDED
    #define VECTOR_HPP_INCLUDED
    
    #include "size.hpp"
    
    template <class T>
    class vector : public size<T>
    {
        public:
        vector(int size);
        ~vector();
        int GetSize() {return m_size;}
        T &operator[] (int index);
    
        private:
        T *m_data;
        int m_size;
    };
    
    template <class T>
    vector<T>::vector(int size)
    :m_size(size)
    {
        m_data=new T[m_size];
    }
    
    template <class T>
    vector<T>::~vector()
    {
        delete []m_data;
    }
    
    template <class T>
    T &vector<T>::operator[] (int index)
    {
        return m_data[index];
    }
    
    #endif // VECTOR_HPP_INCLUDED
    

    size.hpp

    #ifndef SIZE_HPP_INCLUDED
    #define SIZE_HPP_INCLUDED
    
    template <class T>
    class size
    {
        public:
        size();
        virtual ~size();
        void change_size(T &array,int length_old,int extension);
    };
    
    #endif // SIZE_HPP_INCLUDED
    

    size.cpp

    #include <iostream>
    #include <string>
    #include "size.hpp"
    
    template <class T>
    size<T>::size()
    {
    
    }
    
    template <class T>
    size<T>::~size()
    {
    
    }
    
    template <class T>
    void size<T>::change_size(T &array,int length_old,int extension)
    {
        T *cache=new T[length_old];
        for (int i=0;i<length_old;i++)
        {
            cache[i]=array[i];
        }
        delete []array;
        array=NULL;
        array=new T[length_old+extension];
        for (int i=0;i<(length_old+extension);i++)
        {
            array[i]=cache[i];
        }
        delete []cache;
    }
    

    Dankeschön schon mal im Voraus.



  • mit size.hpp und size.cpp sieht es auch nicht viel anders aus, als mit anderen templates. gewöhn dir an, einfach alles in eine header datei zu stopfen. auch wenn's nicht besonders schön aussieht, aber zumindest verliert man nicht so schnell den überblick...

    (genauer: deine size<T>::~size() wird wahrscheinlich nach dem restlichen zeug compiliert, der linker rafft es nicht, und wirft mit fehlermeldungen um sich)



  • Stromberg schrieb:

    ...Und irgendwie is des doch hässlich alles in eine ".hpp" reinzuschreiben?
    Dankeschön schon mal im Voraus.

    "So sind nunmal die bekackten Regeln !" (Walter Sobchak) 😃

    Die Regel lautet allerdings nicht "Alles muss in die Header", sondern (in etwa) "Der Compiler muss zum Zeitpunkt der Nutzung eines template-Konstrukts dessen Implementierung sehen"...
    und da bietet sich einfach die "Implementierung vor Ort" an ... Du kannst sie ja auch in die Klasse selbst schreiben ... machts ein wenig kürzer.

    #include "size.hpp"
    
    template <class T>
    class vector : public size<T>
    {
        public:
        vector(size_t size) :m_size(size), m_data(size ? new T[size] : 0) {}
        ~vector() { delete []m_data; }
        int GetSize() {return m_size;}
        T &operator[] (size_t index) { return m_data[index]; }
        private:
        T *m_data;
        size_t m_size;
    };
    

    finde ich jetzt nicht besonders häßlich...

    BTW: Ich habe size, index und m_size mal einen anderen Typ verpasst ... negativ sollen sie schließlich nicht sein, oder ? 😉 Allerdings solltest Du Dir noch ein paar Bereichsprüfungen überlegen (wie soll sich ein vector v(0); verhalten ?)

    BTW2: Das machst Du doch wahrscheinlich nur als Lernübung, oder ? Sonst würde ich Dir definitiv den std::vector ans Herz legen.

    BTW3: Wenn sich m_size zu Lebzeiten nicht ändert und zur Compilezteit feststehen, kannst Du das auch als template-Parameter nehmen ... dann T m_data[m_size]; definieren und new/delete vergessen 😃

    Gruß,

    Simon2.



  • Man kann Templates laut Standard in die CPP schreiben (ich sage nur Schlüsselwort "export"), aber dummerweise unterstützt bis auf zwei Compiler auf dieser Welt, keiner das. Also mußt du übelerweise Templates in die Header schreiben, ist einfach so.



  • Okay danke, dann schreib ichs halt in die Header is ja auch kein Welt Untergang.
    @Simon2
    Klar ist das nur so eine Spielerei mit der Klasse vector, bzw. halt nä Übung (siehe Volkard Tutorial). Bin mir auch sicher das der echte vector um einiges professioneller wäre.
    Meinst du echt das jemand einene "vector<int> v(0)" erstellet. Sowas ist doch sowieso sinnlos oder??? Was bringt mir ein "vector<int> v(0)" nichts oder?

    Äh und ich hab gesehen das du die Typen von size,inde,und m_size nun als size_t deklariert hast.
    Ich kann mich erinnern, vor einiger Zeit (2-3Monate) hatte ich auch schon mal die Frage und ich habs bis jetzt immer noch nicht richtig gecheckt. Was genau ist size_t?
    Eine Definition aus einem Buch von mir is folgende:

    size_type ist ein vorzeichenloser ganzzahliger Typ, der die Größe des größten Objekts für das Spechermodell aufnehmen kann.

    size_t ist der Typ des Rückgabewerts des Operators "sizeof" und ist in der Header-Datei <cstddef> definiert. Der konkrete Typ ist implementierungsabhängig. Meist ist size_t ein typedef für unsigned int.

    1. ist hier mit "size_type" "size_t" gemeint?
    2. okay, also bedeutet das doch das size_t immer der größtmögliche Typ auf dem jeweiligen OS\Compiler (???) ist? Also ich weiß das "int" bei manchen Compilern\OS's 2 Byte oder 4 Byte hat. (bei mir 4)
    Aber long z.B. hat doch immer 4 Byte. Long ist doch der größtmögliche Ganzzahl Typ oder? Also könnte ich doch immer statt "size_t" einfach "unsigned long" schreiben?
    3. aber irgendwie kann das nicht stimmen was ich gerade gesagt habe, weil oben steht ja folgendes:

    .........
    Meist ist size_t ein typedef für unsigned int.

    Warum den jetzt bitte ein typdef für "unsigned int" ich hab gedacht immer für den größten Ganzzahligen Datentype, und das ist doch long, long hat doch immer 4 Byte egal wo???
    Und wenn es jetzt aber "unsigned int" wäre, dann könnte das doch 2 Byte oder 4 Byte haben. Also 0 bis 65335 oder 0 bis 4294967295 ???
    4. Also warum nimmt man nicht einfach "unsigned long"???

    Hoffentlich erklärts mir nochmal jemand schön ausführlich 😃
    Weil irgendwie blick ich des net.
    Dankeschön schon mal im Voraus.



  • Stromberg schrieb:

    Okay danke, dann schreib ichs halt in die Header is ja auch kein Welt Untergang.
    @Simon2
    Klar ist das nur so eine Spielerei mit der Klasse vector, bzw. halt nä Übung (siehe Volkard Tutorial). Bin mir auch sicher das der echte vector um einiges professioneller wäre.
    Meinst du echt das jemand einene "vector<int> v(0)" erstellet. Sowas ist doch sowieso sinnlos oder??? Was bringt mir ein "vector<int> v(0)" nichts oder?

    Doch, jede Menge Zugriffsfehler, wenn jemand es verwendet 😉

    1. ist hier mit "size_type" "size_t" gemeint?

    size_type ist ein typedef innerhalb der Allokator-Klasse - bei eigenen Allokatoren kannst du den selber anpassen, beim Standard-Allokator ist es typischerweise size_t.

    2. okay, also bedeutet das doch das size_t immer der größtmögliche Typ auf dem jeweiligen OS\Compiler (???) ist? Also ich weiß das "int" bei manchen Compilern\OS's 2 Byte oder 4 Byte hat. (bei mir 4)
    Aber long z.B. hat doch immer 4 Byte. Long ist doch der größtmögliche Ganzzahl Typ oder? Also könnte ich doch immer statt "size_t" einfach "unsigned long" schreiben?

    Nein, size_t muß nur groß genug sein, um damit jede theoretisch mögliche Größenangabe abfangen zu können. Und wenn da ein unsigned int reicht, brauchst du keinen (potentiell) größeren Typ.

    Warum den jetzt bitte ein typdef für "unsigned int" ich hab gedacht immer für den größten Ganzzahligen Datentype, und das ist doch long, long hat doch immer 4 Byte egal wo???

    long hat nicht immer 4 Byte - es darf auch größer sein (und auch int darf mehr als 4 Byte haben. Der Standard definiert da nur Mindestgerößen.

    4. Also warum nimmt man nicht einfach "unsigned long"???

    Weil int normalerweise die "optimale" Größe für die CPU hat - long-Arithmetik kann da etwas aufwendiger werden. Und der Standard schreibt nicht vor, daß size_t ein 'unsigned int' sein MUSS.



  • Stromberg schrieb:

    ...
    Meinst du echt das jemand einene "vector<int> v(0)" erstellet. Sowas ist doch sowieso sinnlos oder??? Was bringt mir ein "vector<int> v(0)" nichts oder?...

    Mag sein ... aber wenn jemand das (evtl. versehentlich) dennoch tut, kracht's in Deinem Code und Du hast erstmal den schwarzen Peter... 😉
    Außerdem gehört das Handling von Ausnahmesituationen einfach zum sauberen Design.

    @"size_t": Ich nutze size_t immer da, wo es um Speichergrößen geht. Damit bin ich auf der sicheren Seite, dass weder negative Werte angenommen werden, noch, dass ich einen "Überlauf" bekomme (Plattform könnte vielleicht 8 Byte adressieren, mein gewählter Typ (evtl. int) ist hier aber als 4 Byte definiert - ein Inkrement auf 0xFFFFFFFF führt also zu 0x0 statt zu 0x100000000 wie erwartet und technisch möglich).

    Langer Rede kurzer Sinn: size_t nimmt Dir die Beschäftigung mit all den Fragen ab, mit denen Du Dich da rumquälst. 😃
    Da sorgt der Compiler dann für...

    Gruß,

    Simon2.



  • Ist ein Arzt anwesend? Irgendwie klingt der Beitrag ziemlich verzweifelt. 😃

    Ok zu den Punkten:
    1. <klasse>::size_type ist in vielen Klassen und Templates der Standardbibliothek vorgegeben und ein typedef auf size_t. Damit ist (z.B.) string::size_type ein size_t.

    2. Er kann die Größe des größten möglichen Objekts aufnehmen, nicht die größte Zahl die vom System repräsentiert werden kann. Das heisst im Klartext, dass Du gerne mit größeren Zahlen als size_t unterstützt rechnen kannst, dennoch wirst Du vom Betriebssystem nie mehr als (z.B.) 4 GB am Stück bekommen. In diesem Fall müsste size_t nur 32 Bit haben, obwohl die Plattform das Rechnen bis 128 Bit unterstützen kann (alles beispielhaft).

    Demnach kannst Du nicht einfach unsigned long schreiben, da size_t durchaus kleiner als long sein könnte.

    3. Long hat nicht immer 4 Byte egal wo. Long ist lediglich so groß wie oder größer als Int. Allerdings steckt in der zitierten Aussage natürlich auch die Prämisse, dass dort, wo "size_t" ein typedef für "unsigned int" ist, auch genug Platz in "unsigned int" zur Verfügung steht. Aber dort steht schließlich auch nicht "immer", sondern "meist".

    4. siehe 2.

    Zu Deinem Vector(0):
    Natürlich ist das sinnlos, aber Du musst immer damit rechnen dass der Anwender Dein Feind ist und Sachen macht, die Du Dir nie vorstellen könntest. Aber das ist IMHO auch logisch, denn jeder kennt seine eigene Anwendung und weiss wie er sie bedienen sollte, und damit unbewusst auch wie man sie nicht bedienen darf. Unbedarften Benutzern (und sei Benutzer in dem Sinne dass ein Entwickler Deine Klasse benutzt) fällt immer noch was ein was Du übersehen hast, glaube mir 😉

    EDIT:
    Und beim nächsten Mal schreibe ich erst den Beitrag zuende und verlasse dann für 10 Minuten das Büro :p


Anmelden zum Antworten