Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » Template typ als typ fuer Template

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 <
000
14.02.2005, 13:28 Uhr
ABC_Freak



Hi C gurus :-)

Ich hab folgendes problem:
Ich hab zum einen ein listen interface (siehe class List) und eine implementierung dazu die ArrayList (siehe class ArrayList) soweit so gut im normalfall funktionieren diese gut.
wenn ich jetzt aber eine Liste von Listen machen will steigt mir der compiler (gcc) aus mit einer fuer mich nicht wirklich aussagekraeftigen fehlermeldung (im constructor fuer Blob die die liste eigentlich verwenden will):


Code:
compiling blob.cpp (g++)
arraylist.h: In instantiation of `ArrayList<List<Blob::Point>*>':
blob.cpp:26: instantiated from here



jetzt zu meinen fragen:

1. was will mir der compiler sagen (das ich da eine instantz anlege wenn ich new mache is mir schon klar und eigentlich sinn der sache)

2. was hab ich mal wieder falsch gemacht? bzw. wie gehoerts gemacht (ausser dem dass ein zeiger auf eine Liste von Zeigerlisten vielleicht nicht ganz so schoen ist)

3. ist etwas wie List< List<int> > ueberhaupt erlaubt? da ich ja quasie rekursiv als typ fuer das Template nochmal ein Template mit einem bestimten typ angebe

Einfach die standartliste zu verwenden ist kein workaround weil es fuer mich hier eher um ein grundsaetzliches problem handelt (neben meiner rechtschreibung)

Vielen Dank fuer Eure hilfe

euer Freak


im folgenden ist der code dazu (implementierungen dementsprechend weggelassen):


C++:
template <class T>
class List{
public:
    virtual void add(T o) = 0;
    virtual T get(int index) const = 0;
    virtual void remove(int index) = 0;
};


template <class T>
class ArrayList : public List<T>
{
public:
    ArrayList(int startSize=10, double extendValue=10, bool stepOrFactor=true);

    ~ArrayList();
    
    void add(T o);
    T get(int index) const;
    void remove(int index);

private:
    int maxCount;
    int curCount;
    T * field;
    double extendValue;
    
    void(ArrayList::*extender)(double);
    
    void extendStep(double stepSize);
    void extendFactor(double fac);
};

class Blob{
public:
    Blob();
    ~Blob();
    void addPoint(int x, int y);
    
private:
    typedef struct{
        int x;
        int y;
    } Point;
    List<List<Point>* >* sets;
};

Blob::Blob()
{
    // a list with the initial size 10 which will be extended by the factor 2 if needed
    sets = new ArrayList< List<Blob::Point>* >(10,2,false); //<- Compiler Error
}

 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
14.02.2005, 13:37 Uhr
0xdeadbeef
Gott
(Operator)


Polymorphe Klassen brauchen einen virtuellen Destruktor:

C++:
template <class T>
class List{
public:
    virtual ~List();

    virtual void add(T o) = 0;
    virtual T get(int index) const = 0;
    virtual void remove(int index) = 0;
};


template <class T>
class ArrayList : public List<T>
{
public:
    ArrayList(int startSize=10, double extendValue=10, bool stepOrFactor=true);

    virtual ~ArrayList();
    
    void add(T o);
    T get(int index) const;
    void remove(int index);

private:
    int maxCount;
    int curCount;
    T * field;
    double extendValue;
    
    void(ArrayList::*extender)(double);
    
    void extendStep(double stepSize);
    void extendFactor(double fac);
};


Das ist so das erste, das mir auffällt. Wenns das nicht ist, bräuchte ich den gesamten Compiler-Output.
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra

Dieser Post wurde am 14.02.2005 um 13:38 Uhr von 0xdeadbeef editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
14.02.2005, 13:47 Uhr
ABC_Freak



bischetoen:

(was mir grad auffaelt ist das "undefined reference to ArrayList(int,double,bool) obwohls sowohl declariert, definiert und included is. kann natuerlich sein das das durch den fehler vorher ausgeloest wird)

cd '/home/lutz/projekte/test3' && QTDIR="/usr/lib/qt3" gmake -k
cd src && gmake -f Makefile
test -d ../bin/ || mkdir -p ../bin/
g++ -o ../bin/test3 test3.o main.o KontrastFilter.o grayfilter.o blackwhitefilter.o controlwidget.o prototype.o uifilterwrapper.o PictureFilter.o filterrow.o list.o arraylist.o saliencyfilter.o blob.o moc_test3.o moc_controlwidget.o -L/usr/lib/ -L/usr/lib/qt3/lib/ -L/usr/X11R6/lib/ -lqt-mt -lXext -lX11 -lm -lpthread
blob.o(.text+0xdc): In function `Blob::Blob[in-charge]()':
: undefined reference to `ArrayList<List<Blob::Point>*>::ArrayList[in-charge](int, double, bool)'
blob.o(.text+0x14c): In function `Blob::Blob[not-in-charge]()':
: undefined reference to `ArrayList<List<Blob::Point>*>::ArrayList[in-charge](int, double, bool)'
collect2: ld returned 1 exit status
gmake[1]: *** [../bin/test3] Error 1
gmake[1]: Target `first' not remade because of errors.
gmake: *** [sub-src] Error 2
gmake: Target `first' not remade because of errors.
*** Exited with status: 2 ***
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
14.02.2005, 13:51 Uhr
ABC_Freak



ok das mit dem virtual hat doch etwas ausgemacht (ich dachte ich brauch den virtuellen constructor nur wenn da drin wirklich was gemacht wird bei List is das ja nich der fall aber ok man lernt ja nie aus)

der output is jetzt etwas kuerzer (der instantz error is weg):

cd '/home/lutz/projekte/test3' && QTDIR="/usr/lib/qt3" gmake -k
cd src && gmake -f Makefile
test -d ../bin/ || mkdir -p ../bin/
g++ -o ../bin/test3 test3.o main.o KontrastFilter.o grayfilter.o blackwhitefilter.o controlwidget.o prototype.o uifilterwrapper.o PictureFilter.o filterrow.o list.o arraylist.o saliencyfilter.o blob.o moc_test3.o moc_controlwidget.o -L/usr/lib/ -L/usr/lib/qt3/lib/ -L/usr/X11R6/lib/ -lqt-mt -lXext -lX11 -lm -lpthread
blob.o(.text+0xdc): In function `Blob::Blob[in-charge]()':
: undefined reference to `ArrayList<List<Blob::Point>*>::ArrayList[in-charge](int, double, bool)'
blob.o(.text+0x14c): In function `Blob::Blob[not-in-charge]()':
: undefined reference to `ArrayList<List<Blob::Point>*>::ArrayList[in-charge](int, double, bool)'
collect2: ld returned 1 exit status
gmake[1]: *** [../bin/test3] Error 1
gmake[1]: Target `first' not remade because of errors.
gmake: *** [sub-src] Error 2
gmake: Target `first' not remade because of errors.
*** Exited with status: 2 ***
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
14.02.2005, 14:02 Uhr
virtual
Sexiest Bit alive
(Operator)


Du hast den ArrayList Konstruktor nicht definiert (Implementierung fehlt, daher der Linkererror)
--
Gruß, virtual
Quote of the Month
Ich eß' nur was ein Gesicht hat (Creme 21)
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
005
14.02.2005, 14:07 Uhr
0xdeadbeef
Gott
(Operator)


Hm. Ich schieß grad ins Blaue, aber du weißt, dass bei templates der gesamte Code in den Header muss, oder?
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
006
14.02.2005, 14:45 Uhr
ABC_Freak



ne wuste ich nich... und verstehen tu ichs gleich noch weniger aber egal war ein volltreffer

ging jetzt sogar (allerdings musste ich das ganze projekt komplett neu kompilieren da der linker wohl nich so ganz auf der hoehe war)

grosses danke ans helferlein: DANKE

schade das ich nich java machen darf :-( da gibts solche problemen von wegen was in welche datei schon mal garnich.

fuer alle die wissen wollen wie "arraylist.h" aussieht hier:


C++:
template <class T>
class ArrayList : public List<T>
{
public:
    ArrayList(int startSize=10, double extendValue=10, bool stepOrFactor=true);

    virtual ~ArrayList();
    
    void add(T o);
    T get(int index) const;
    void remove(int index);

private:
    int maxCount;
    int curCount;
    T * field;
    double extendValue;
    
    void(ArrayList::*extender)(double);
    
    void extendStep(double stepSize);
    void extendFactor(double fac);
};

template <class T>
ArrayList<T>::ArrayList(int startSize, double extendValue, bool stepOrFactor)
: List<T>()
{
    maxCount = startSize;
    curCount = 0;
    field = new T[maxCount];
    this->extendValue = extendValue;
    
    if(stepOrFactor)
        extender = &ArrayList::extendStep;
    else
        extender = &ArrayList::extendFactor;
}

template <class T>
ArrayList<T>::~ArrayList()
{
    delete [] field;
}

template <class T>
void ArrayList<T>::add(T o){
    // check bounds
    if(curCount>=maxCount)
        (this->*extender)(extendValue);
        
    // add the element to the end
    field[curCount++] = o;
}
template <class T>
void ArrayList<T>::remove(int index){
    int size = sizeof(T);
    // copy the appendix after the index one slot to front
    for(int i=index+1; i<curCount; ++i){
        field[i-1] = field[i];
    }
    
}
template <class T>
T ArrayList<T>::get(int index) const {
    return field[index];
}
template <class T>
void ArrayList<T>::extendFactor(double fac){
    // make new one
    T * newField = new T[ (int)(maxCount*extendValue)];
    
    // copy content
    memcpy(newField,field,curCount*sizeof(T));
    
    // delete old
    delete [] field;
    
    // point to new
    field = newField;
}


template <class T>
void ArrayList<T>::extendStep(double stepSize){
    // make new one
    T * newField = new T[(int)(maxCount+extendValue)];
    
    //copy content
    memcpy(newField,field,curCount*sizeof(T));
    
    // delete old
    delete [] field;
    
    // point to new
    field = newField;
}



 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
007
14.02.2005, 20:26 Uhr
0xdeadbeef
Gott
(Operator)


Das Problem ist, dass der template-Code halt eine Vorlage (template == Vorlage) ist, die erst zum eigentlichen Code konkretisiert werden muss. Eine template selbst ist nicht kompilierbar - wenn du objdump auf arraylist.o loslässt, wirst du feststellen, dass die Datei keine Symbole enthält. Was in die Objektdateien reinkommt, ist der konkretisierte template-Code, aber damit der Compiler den erstellen kann, muss er den ursprünglichen template-Code kennen. Und deswegen muss die Implementierung einer template ebenfalls in den Header.

Eine gängige Möglichkeit, den template-code trotzdem auf zwei Dateien aufzuteilen ist:

C++:
// foo.hh
#ifndef INCLUDED_FOO_HH
#define INCLUDED_FOO_HH

template<typename t> class foo {
public:
  void bar();
};

#include "foo.tcc"

#endif



C++:
// foo.tcc
template<typename t> void foo<t>::bar() { }


Aber das ist ja im Grunde das selbe.
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 <     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: