template klassen



  • Ich hab mir zu dem Thema nun schon mehrere Tutorials angeschaut, aber das mit den templates kapier ich net!

    class xyz
    {
    private:
    int a;
    int b;
    
    public:
    xyz
    {
    // Ich bin ein konstruktor
    };
    
    ~xyz
    {
    //Ich bin ein Destruktor
    };
    
    int abc
    {
    //ich bin eine der Methoden
    };
    };
    

    Jetzt nur mal so als Bsp...

    Wenn ich nun eine template Klasse machen will, fang ich so an:

    template <class T>
    class xyz
    {
    //Was nun???
    };
    

    An manchen stellen müsste ich nun int durch T ersetzen, aber wo? (auch allgemein, wenn es andere Variablenarten sind)



  • Member-Elemente kannst du deklarieren wo immer du willst, nur auf die Zugriffsebene muss geachtet werden. Ob es eine Template-Klasse ist oder nicht, spielt keine Rolle:

    template<class T>
    struct A
    {
        //public
        int a, b, c;
    
        A() { }
    
        char a1;
    
    private:
        T d, e, f;
    };
    


  • Kommt drauf an was du machen willst. Ein einfaches Beispiel wäre eine Listenklasse. Man will sich ja nicht für jeden Datentyp eine eigene Liste schreiben, also macht man einmal eine Klasse für den Platzhalter T und kann sie dann nachher für alle geeigeneten Tyen wiederverwenden. Kann ein Buch aber bestimmt besser erklären.



  • Hallo,

    ness schrieb:

    An manchen stellen müsste ich nun int durch T ersetzen, aber wo? (auch allgemein, wenn es andere Variablenarten sind)

    Nunja, ein Template erstellt man ja nicht einfach so, sondern um eine Klasse generisch zu machen, sodass sie mit beliebigen Typen arbeiten kann. Wenn du z.B. einen Vector (eine Art Ersatz für die C-Arrays) schreiben möchtest, dann wäre es ja sinnlos, einmal zu schreiben:

    class MyVector_int
    {
    public:
       ...
    private:
       int* m_data;   //Zeiger auf int-Array
       size_t m_size;
    };
    

    Und dann

    class MyVector_double
    {
    public:
       ...
    private:
       double* m_data;   //Zeiger auf double-Array
       size_t m_size;
    };
    

    usw. Statt dessen schaust du dir an, welcher Typ sich immer ändert. Das wäre hier also int*, double* usw. Dieser wird nun durch T* ersetzt:

    template <class T> class MyVector
    {
    public:
       ...
    private:
       T* m_data;   //Zeiger auf T-Array
       size_t m_size;
    };
    

    Entsprechend wird int etc. auch bei den Memberfunktionen durch T ersetzt, die mit dem Typ arbeiten, also z.B. das n-te Element zurückgeben.

    Dahingegen bleibt m_size hier immer vom Typ size_t, da die Größe des Vectors ja immer als positive Zahl ausgedrückt wird, egal ob darin nun ints, doubles oder ganze Klasssen gespeichert werden. Du musst also nur dort T einsetzen, wo du später mithilfe des Templates einen beliebigen Typ einsetzen willst.

    [Edit:] Zu langsam...

    Sven



  • @ sven25: Genau das will ich!



  • Klappt aber nicht!
    vector.h:

    template<class T>
    class Vector
    {
    private:
    
    T *m_data;
    int m_size;
    static const int GROW_SIZE=10;
    public:
    
    Vector(int size)
    {
    m_size=size;
    m_data=new T[m_size];
    };
    
    ~Vector()
    {
    delete[] m_data;
    };
    
    Vector(const Vector &derAndereVector)
       {
          m_size=derAndereVector.m_size;
          m_data=new T[m_size];
          for(int i=0;i<m_size;++i)
             m_data[i]=derAndereVector.m_data[i];
       };
    
    Vector &operator=(const Vector &derAndereVector)    
       {
          if(&derAndereVector!=this)
          {
             delete m_data;
             m_size=derAndereVector.m_size;
             m_data=new T[m_size];
             for(int i=0;i<m_size;++i)
                m_data[i]=derAndereVector.m_data[i];
          };
          return *this;
       };
    
    double& operator[] (int index)
    {
    return m_data[index];
    };
    
    int getsize()
    {
    return m_size;
    };
    
    int grow(int newsize)
    {
        if(newsize>m_size)
          {
             newsize+=GROW_SIZE;
             T *newData=new T[newsize];
             for(int i=0;i<m_size;++i)
                newData[i]=m_data[i];
                delete[] m_data;
             m_size=newsize;
             m_data=newData;
          };
    };
    
    int movedown (int start, int end, int newstart)
       {
       const int verschieb=start-newstart;
       for (int i=start; i<end; i=i+1)
       m_data[i-verschieb]=m_data[i];   
       };  
    };
    
    class SortedArray
    {
    #include "vector.h"
    private:
       Vector<double> m_data;
       int m_size;
       int findIndex(const double &tofind)
       {
           for (int i=0; i<m_size; i=i+1)
           if (m_data[i]==tofind) return i;
           return -1;
       };        
    public:
       SortedArray()
       :m_data(10)
       {
          m_size=0;
       };
    
    double *find(const double &toFind)
       {
          int found=findIndex(toFind);
          if(found!=-1)
             return &m_data[found];
          else
             return 0;
       };
    
    bool has(double &toFind)
       {
          return find(toFind)!=0;
       };
    
    int insert(const double &toInsert)
       {
          if(!has(toInsert))
          {
             m_data.grow(m_size+1);
             m_data[m_size]=toInsert;
             m_size=m_size+1;
          };
       };
    
    int remove(const double &toRemove)
       {
          int found=findIndex(toRemove);
          if(found!=-1)
          {
             m_data.movedown(found+1,m_size,found);
             --m_size;
          };
       };
    };
    

    Indirekt müsste das doch auch template sein, weil es ja mit vectors arbeitet, oder? Ich hab halt versucht das auchnoch template zu machen und dabei einfach überall wo double satbd T geschrieben und als erste Zeile halt

    template <class T>
    

    geschrieben! (Was aber net nötig ist, oder?)

    main.cpp

    include <iostream>
    using namespace std;
    #include "SortedArray.h"
    
    int main()
    {
        SortedArray<string> s;
        s.insert("Hans");
        s.insert("Klaus");
        s.insert("ich");
        s.insert("Fritz");
        s.insert("Anna");
       for(int i=0;i<s.getSize();++i)
          cout<<s[i]<<endl;
    };
    

    Bei der Syntaxüberprüfung krieg ich:

    3 C:\DOKUME1\TOM\EIGENE1\C__1\Projekte\TELEFO1\main.cpp In file included from main.cpp
    C:\DOKUME1\TOM\EIGENE1\C__1\Projekte\TELEFO1\SortedArray.h In member function int SortedArray::insert(const double&)': 37 C:\\DOKUME~1\\TOM\\EIGENE~1\\C__~1\\Projekte\\TELEFO~1\\SortedArray.h no matching function for call toSortedArray::has( const double&)'
    error C:\DOKUME1\TOM\EIGENE1\C__1\Projekte\TELEFO1\SortedArray.h:31 candidates are: bool SortedArray::has(double&)
    C:\DOKUME1\TOM\EIGENE1\C__1\Projekte\TELEFO1\main.cpp In function int main()': 7 C:\\DOKUME~1\\TOM\\EIGENE~1\\C__~1\\Projekte\\TELEFO~1\\main.cpp non-template typeSortedArray' used as a template
    7 C:\DOKUME1\TOM\EIGENE1\C__1\Projekte\TELEFO1\main.cpp ISO C++ forbids declaration of `s' with no type
    ... ... 😞

    Was ist nun schon wieder falsch?



  • Hallo,

    SortedArray ist kein Template, du nutzt es aber als solches. Das kann natuerlich
    nicht funktionieren.

    Du hast ja bereits gesagt, wie es aussehen muesste, damit es funktioniert.
    Bleibt nur die Frage, sollte SortedArray nicht besser von Vector erben? Da
    faellt mir ein, waere hier der Name SortedVector nicht angebrachter?

    Keine Garantie, dass ich irgendetwas uebersehen habe 🙂

    #include "vector.h"
    
    template<class T>
    class SortedArray : public Vector<T>
    {
    private:
       int findIndex(const T &tofind)
       {
           for (int i=0; i<m_size; i=i+1)
           if (m_data[i]==tofind) return i;
           return -1;
       };        
    public:
       SortedArray()
       : Vector(0)
       {}
    
    T *find(const T &toFind)
       {
          int found=findIndex(toFind);
          if(found!=-1)
             return &m_data[found];
          else
             return 0;
       };
    
    bool has(const T &toFind)
       {
          return find(toFind)!=0;
       };
    
    //hier wird gar nichts zurueckgegeben, gewollt? sollte es void sein?
    int insert(const T &toInsert)
       {
          if(!has(toInsert))
          {
             m_data.grow(m_size+1);
             m_data[m_size]=toInsert;
             m_size=m_size+1;
          };
       };
    
    //siehe kommentar von insert
    int remove(const T &toRemove)
       {
          int found=findIndex(toRemove);
          if(found!=-1)
          {
             m_data.movedown(found+1,m_size,found);
             --m_size;
          };
       };
    };
    

    Jetzt muss natuerlich m_data und m_size entweder in den protected-Bereich der
    Vector-Klasse, oder du bietest entsprechende Memberfunktionen an, die dir
    eben diese liefern.

    mfg
    v R


Anmelden zum Antworten