[c++] "Riferimento non definito a" costruttore di classi template


0 Answers

Dovrai definire le funzioni all'interno del tuo file di intestazione.
Non è possibile separare la definizione delle funzioni del modello nel file di origine e le dichiarazioni nel file di intestazione.

Quando un modello viene utilizzato in un modo che attiva la sua intstantation, un compilatore deve vedere quella particolare definizione di template. Questo è il motivo per cui i modelli sono spesso definiti nel file di intestazione in cui sono dichiarati.

Riferimento:
C ++ 03 standard, § 14.7.2.4:

La definizione di un modello di funzione non esportato, un modello di funzione membro non esportato o una funzione membro non esportata o membro dati statici di un modello di classe deve essere presente in ogni unità di traduzione in cui viene esplicitamente istanziata.

MODIFICARE:
Per chiarire la discussione sui commenti:
Tecnicamente, ci sono tre modi per aggirare questo problema di collegamento:

  • Per spostare la definizione nel file .h
  • Aggiungi istanze esplicite nel file .cpp .
  • #include il file .cpp che definisce il modello nel file .cpp usando il modello.

Ognuno di loro ha i suoi pro e contro,

Spostare le definizioni nei file di intestazione può aumentare le dimensioni del codice (i compilatori dei moderni possono evitarlo) ma aumenterà sicuramente il tempo di compilazione.

L'utilizzo dell'approccio di istanziazione esplicita si sta spostando su un approccio macro-tradizionale. Un altro svantaggio è che è necessario sapere quali tipi di template sono necessari al programma. Per un programma semplice questo è facile ma per un programma complicato diventa difficile determinarlo in anticipo.

Pur includendo i file cpp è confuso allo stesso tempo condivide i problemi di entrambi gli approcci di cui sopra.

Trovo il primo metodo il più facile da seguire e implementare e quindi sostengo l'utilizzo.

Question

Questa domanda ha già una risposta qui:

Non ho idea del motivo per cui questo è felice, dal momento che penso di avere tutto correttamente dichiarato e definito.

Ho il seguente programma, progettato con modelli. È una semplice implementazione di una coda, con le funzioni membro "aggiungi", "sottrazione" e "stampa".

Ho definito il nodo per la coda nel fine "nodo_colaypila.h":

#ifndef NODO_COLAYPILA_H
#define NODO_COLAYPILA_H

#include <iostream>

template <class T> class cola;

template <class T> class nodo_colaypila
{
        T elem;
        nodo_colaypila<T>* sig;
        friend class cola<T>;
    public:
        nodo_colaypila(T, nodo_colaypila<T>*);

};

Quindi l'implementazione in "nodo_colaypila.cpp"

#include "nodo_colaypila.h"
#include <iostream>

template <class T> nodo_colaypila<T>::nodo_colaypila(T a, nodo_colaypila<T>* siguiente = NULL)
{
    elem = a;
    sig = siguiente;//ctor
}

Successivamente, la definizione e la dichiarazione della classe del modello di coda e le sue funzioni:

"Cola.h":

#ifndef COLA_H
#define COLA_H

#include "nodo_colaypila.h"

template <class T> class cola
{
        nodo_colaypila<T>* ult, pri;
    public:
        cola<T>();
        void anade(T&);
        T saca();
        void print() const;
        virtual ~cola();

};


#endif // COLA_H

"Cola.cpp":

#include "cola.h"
#include "nodo_colaypila.h"

#include <iostream>

using namespace std;

template <class T> cola<T>::cola()
{
    pri = NULL;
    ult = NULL;//ctor
}

template <class T> void cola<T>::anade(T& valor)
{
    nodo_colaypila <T> * nuevo;

    if (ult)
    {
        nuevo = new nodo_colaypila<T> (valor);
        ult->sig = nuevo;
        ult = nuevo;
    }
    if (!pri)
    {
        pri = nuevo;
    }
}

template <class T> T cola<T>::saca()
{
    nodo_colaypila <T> * aux;
    T valor;

    aux = pri;
    if (!aux)
    {
        return 0;
    }
    pri = aux->sig;
    valor = aux->elem;
    delete aux;
    if(!pri)
    {
        ult = NULL;
    }
    return valor;
}

template <class T> cola<T>::~cola()
{
    while(pri)
    {
        saca();
    }//dtor
}

template <class T> void cola<T>::print() const
{
    nodo_colaypila <T> * aux;
    aux = pri;
    while(aux)
    {
        cout << aux->elem << endl;
        aux = aux->sig;
    }
}

Quindi, ho un programma per testare queste funzioni come segue:

"Main.cpp"

#include <iostream>
#include "cola.h"
#include "nodo_colaypila.h"

using namespace std;

int main()
{
    float a, b, c;
    string d, e, f;
    cola<float> flo;
    cola<string> str;

    a = 3.14;
    b = 2.71;
    c = 6.02;
    flo.anade(a);
    flo.anade(b);
    flo.anade(c);
    flo.print();
    cout << endl;

    d = "John";
    e = "Mark";
    f = "Matthew";
    str.anade(d);
    str.anade(e);
    str.anade(f);
    cout << endl;

    c = flo.saca();
    cout << "First In First Out Float: " << c << endl;
    cout << endl;

    f = str.saca();
    cout << "First In First Out String: " << f << endl;
    cout << endl;

    flo.print();
    cout << endl;
    str.print();

    cout << "Hello world!" << endl;
    return 0;
}

Ma quando costruisco, il compilatore genera errori in ogni istanza della classe template:

riferimento non definito a `cola (float) :: cola () '... (in realtà è cola' <'float'> ':: cola (), ma questo non mi permette di usarlo in quel modo.)

E così via. Complessivamente, 17 avvisi, contando quelli per le funzioni membro chiamate nel programma.

Perchè è questo? Tali funzioni e costruttori sono stati definiti. Ho pensato che il compilatore potesse sostituire la "T" nel modello con "float", "string" o qualsiasi altra cosa; questo era il vantaggio dell'uso di modelli.

Ho letto da qualche parte qui che dovrei mettere la dichiarazione di ogni funzione nel file di intestazione per qualche ragione. È giusto? E se sì, perché?

Grazie in anticipo.




Related