Domanda

Ricevo errori di collegamento del seguente tipo:

Festival.oggetto:errore LNK2019:simbolo esterno non risolto "pubblico:void __thiscall albero :: aggiungi (prezzo di classe &) "(? Aggiungi@? $ albero@vprice @@@@ qaexaavprice @@@ z) Rifredito nella funzione __Catch $? Addband@Festival @@ Qae? AW4STUSTYPE @@ hhh@z $ 0

Pensavo che avesse a che fare con il meccanismo try-catch, ma da allora mi è stato detto il contrario.Questa è una versione aggiornata della domanda.

Sto utilizzando Visual Studio 2008, ma ho problemi simili in g++.

Il codice rilevante:

In Festival.cpp

#include "Tree.h"
#include <exception>

using namespace std;

class Band{
public:
    Band(int bandID, int price, int votes=0): bandID(bandID), price(price), votes(votes){};
...
private:
...

};

class Festival{
public: 
    Festival(int budget): budget(budget), minPrice(0), maxNeededBudget(0), priceOffset(0), bandCounter(0){};
    ~Festival();
    StatusType AddBand(int bandID, int price, int votes=0);
    ...

private: 
    Tree<Band> bandTree;
    ...

};

StatusType Festival::AddBand(int bandID, int price, int votes){
    if ((price<0)||(bandID<0)){
        return INVALID_INPUT;
    }
    Band* newBand=NULL;
    try{
        newBand=new Band(bandID,price-priceOffset,votes);
    }
    catch(bad_alloc&){return ALLOCATION_ERROR;}
    if (bandTree.find(*newBand)!=NULL){
        delete newBand;
        return FAILURE;
    }
bandTree.add(*newBand);
....
}

In Tree.h:

template<class T>
class Tree{
public:
    Tree(T* initialData=NULL, Tree<T>* initialFather=NULL);
    void add(T& newData);
....
private:
....
};

È interessante notare che non ho errori di collegamento quando provo a utilizzare le funzioni Tree quando il tipo T è un tipo primitivo come un int.

È stato utile?

Soluzione

Esiste Tree.cpp? Se c'è, forse hai dimenticato di collegarlo? Dov'è l'implementazione di Tree :: add? Inoltre non vedo dove chiami Tree :: add. Immagino che dovrebbe essere all'interno della dichiarazione try, subito dopo il nuovo?

Solo un promemoria:

Per la maggior parte dei compilatori (ovvero quelli che esercitano una compilazione separata) l'implementazione delle funzioni membro di una classe modello deve essere visibile durante la compilazione del file sorgente che utilizza la classe modello. Di solito le persone seguono questa regola inserendo l'implementazione delle funzioni membro all'interno del file header.

Forse Tree :: add non è all'interno dell'intestazione? Quindi una possibile soluzione nel caso discusso sarà quella di mettere Tree :: add implementazione all'interno del file header.

La differenza tra le classi normali e le classi template esiste perché le classi template non sono " real " classi - è, beh, un modello. Se avessi definito la tua classe Tree come una classe normale, il compilatore avrebbe potuto usare subito il tuo codice. Nel caso di un modello, il compilatore prima & Quot; scrive & Quot; per te la vera classe, sostituendo i parametri del modello con i tipi che hai fornito. Ora, il compilatore compila i file cpp uno per uno. Non è a conoscenza di altri file cpp e non può utilizzare nulla da altri file cpp. Supponiamo che l'implementazione di Tree: add assomigli a questo:

void Tree::add(T& newData)
{
    newData.destroyEverything();
}

È totalmente legittimo fintanto che la tua T ha il metodo di distruggere Tutto. Quando il compilatore compila Class.cpp vuole essere sicuro di non fare nulla con T che non sa. Ad esempio Tree<int> non funzionerà perché int non ha destroyEverything. Il compilatore proverà a scrivere il codice con int anziché T e scoprirà che il codice non viene compilato. Ma dal momento che il compilatore & Quot; vede & Quot; solo l'attuale cpp e tutto ciò che include, non sarà in grado di validare la funzione add, poiché è in un cpp separato.

Non ci saranno problemi con

void Tree::add(int& newData)
{
    newData.destroyEverything();
}

implementato in un cpp separato perché il compilatore sa che int è l'unico tipo accettabile e può " contare su se stesso " che quando arriva a compilare Tree.cpp troverà l'errore.

Altri suggerimenti

Sei sicuro che try / catch abbia qualcosa a che fare con esso? Cosa succede se si commentano semplicemente le righe Tree::add(class Price &) e <=>, si lascia il resto del codice così com'è e lo si crea?

È possibile che manchi la libreria che definisce <=> dalla tua linea di collegamento.

Aggiornamento: l'uso delle funzioni Tree con un tipo primitivo non provoca un errore di collegamento. Ho aggiornato la mia domanda alla luce di alcune delle cose che sono state dette.

Come altri hanno affermato, devi mostrare l'implementazione di Treee :: add () e dirci come lo stai collegando.

Su un punto non correlato, se stai usando costrutti come:

  Band* newBand=NULL;
    try{
        newBand=new Band(bandID,price-priceOffset,votes);
    }
    catch(bad_alloc&){return ALLOCATION_ERROR;}

in tutto il tuo codice, stai francamente perdendo tempo. Le probabilità che tu stia arrivando a un punto di esaurimento della memoria in un sistema operativo moderno sono remote e le probabilità che tu faccia qualcosa di utile dopo che è successo sono all'incirca zero. Starai molto meglio semplicemente dicendo:

Band * newBand = new Band ( bandID, price - priceOffset, votes );

ot possibilmente:

Band newBand( bandID, price - priceOffset, votes );

e dimenticando la gestione delle eccezioni in questo caso.

Hai scritto in un commento:

  

L'ho considerato, ma la funzione fa parte di Tree.h e la includo. La funzione definita è: template void Tree :: add (T & Amp; newData); Lo chiamiamo nel modo seguente: priceTree.add (* newPriceNode); considerando che priceTree è Tree, entrambi definiti nel file cpp in questione.

anziché:

priceTree.add(*newPriceNode);

Prova:

priceTree.add(newPriceNode); //no "*" before "newPriceNode"

add () accetta un riferimento a un nodo, non un puntatore a un nodo (secondo la tua definizione di Albero).

Stai ricevendo errori di collegamento, non errori del compilatore.Questo ci dice che il compilatore sapeva che tipo di funzione Tree::add() lo è, ma non aveva una definizione.In Tree.h vedo una dichiarazione della funzione add(), ma non una definizione.Mi sembra strano;qualcuno sa da dove viene Tree.h?

Di solito una classe template viene fornita con le definizioni delle funzioni membro nel file di inclusione, poiché le funzioni devono essere istanziate da qualche parte e la cosa più semplice è che il compilatore istanzia quando viene utilizzato e lascia che sia il linker a risolverlo.Se le definizioni sono in Tree.h, mi aspetto che tutto funzioni come previsto.

Quindi, mi sbilanciarò e suggerirò che le definizioni siano in un file separato, non collegate, e che ci siano disposizioni altrove per istanziare tipi di base come Tree<int>.Questo presumibilmente è per semplificare la compilazione, poiché normalmente queste cose vengono compilate in più posti e ciò richiede tempo.

Ciò che devi fare in tal caso è trovare dove Tree<int> viene istanziato e aggiungi un'istanza per la tua classe.

Potrei essere molto fuori strada qui, ma la mia spiegazione si adatta ai fatti che hai fornito.

Modifica dopo i primi commenti:

I modelli sono un po' più complicati delle normali funzioni, il che di solito non è un vero problema.Se le definizioni per tutte le chiamate fossero in Tree.h, allora Festival.cpp sarebbe in grado di istanziare Tree<Band> e tutto sarebbe bello.Questa è la tecnica abituale e ti imbatti in questo problema perché non la usi.

Quando scrivi una funzione, questa viene compilata e il linker la troverà.Qualsiasi routine che chiami quella funzione deve conoscere il prototipo della funzione, quindi saprà come chiamarla.Quando scrivi un modello, non scrivi nulla che andrà direttamente nel programma, ma qualsiasi utilizzo del modello conta come scrivere tutte le funzioni.

Pertanto, deve esserci qualche utilità Tree<Band> da qualche parte nel tuo programma, perché ci sia a Tree<Band>::add() funzione compilata.La definizione di Tree<T>::add deve essere disponibile al compilatore quando Tree<Band> viene istanziato, perché altrimenti il ​​compilatore non ha idea di cosa compilare.In questo caso, sta generando la chiamata alla funzione, sicuro che ti assicurerai che la funzione sia compilata altrove.

Pertanto, è necessario istanziare Tree<Band> all'interno di un file che ha accesso a entrambe le definizioni di Tree<T> E Band.Ciò probabilmente significa un file che è, o include, Tree.cpp e include Festival.h.

Il linker utilizza già Tree.cpp, ma Tree.cpp non lo ha Tree<Band> definito in esso, quindi non ha significato per il linker.I modelli sono utili solo per il compilatore e il linker opera solo su ciò che il compilatore ha generato dai modelli.

Il modo rapido per risolvere questo problema è prendere le definizioni da Tree.cpp e inserirle in Tree.h.Sfortunatamente, ciò probabilmente aumenterà i tempi di compilazione e collegamento.L'altra tecnica consiste nell'istanziare tutti i template utilizzati in Tree.cpp, in modo che vengano compilati lì.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top