Frage

Ich erhalte Verknüpfung Fehler der folgenden Art:

  

Festival.obj: error LNK2019:   nicht aufgelöstes externes Symbol „public:   nichtig __thiscall Baum :: hinzufügen (Klasse Preis &)“   (? Hinzufügen @? $ Baum @ vPrice @@@@ QAEXAAVPrice @@@ Z)   in Funktion verwiesen   __catch $? AddBand @ Festival @@ QAE? AW4StatusType @@ HHH @ Z $ 0

Früher dachte ich, es mit try-catch-Mechanismus zu tun hat, aber da nichts anderes gesagt worden. Dies ist eine aktualisierte Version der Frage.

Ich bin mit Visual Studio 2008, aber ich habe ähnliche Probleme in g ++.

Der entsprechende Code:

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:
....
};

Interessanterweise ich nicht Verknüpfung Fehler, wenn ich versuche, Baum-Funktionen zu verwenden, wenn Typ T ein primitiver Typ wie ein int ist.

War es hilfreich?

Lösung

Gibt es Tree.cpp? Wenn ja, vielleicht vergessen hat, es zu verbinden? Wo ist :: die Umsetzung des Baumes hinzufügen? Außerdem sehe ich nicht, wo Sie Baum nennen :: hinzufügen. Ich denke, es in der try-Anweisung sein sollte, gleich nach dem neuen?

Nur zur Erinnerung:

Für die meisten Compiler (das heißt solche, die getrennte Sammlung der Praxis), die Umsetzung der Elementfunktionen einer Template-Klasse hat bei der Erstellung der Quelldatei sichtbar sein, der die Vorlage-Klasse verwendet. Normalerweise Menschen folgen dieser Regel durch die Umsetzung der Member-Funktionen innerhalb der Header-Datei setzen.

Vielleicht Baum :: hinzuzufügen, ist nicht in der Kopfzeile? Dann wird eine mögliche Lösung in dem diskutierten Fall wird Baum setzen :: Implementierung innerhalb der Header-Datei hinzuzufügen.

Der Unterschied zwischen regulären Klassen und Template-Klassen gibt es, weil Template-Klassen nicht „real“ Klassen sind - es ist gut, eine Vorlage. Wenn Sie Ihre Tree-Klasse als eine reguläre Klasse definiert hatten, haben die Compiler könnten Ihren Code sofort verwendet. Im Falle einer Vorlage „schreibt“ der Compiler zunächst für Sie die reale Klasse, die Template-Parameter mit den Typen ersetzen Sie geliefert. Nun Compiler kompiliert CPP Dateien nacheinander. Er ist nicht bewusst, andere CPP-Dateien und nichts von anderen CPP-Dateien verwenden kann. Lassen Sie uns sagen, dass Ihre Implementierung von Baum: add sieht wie folgt aus:

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

Es ist völlig legitim, solange Ihr T-Methode destroyEverything hat. Wenn der Compiler kompiliert Class.cpp es will sicher sein, dass Sie nicht mit T nichts tun es nicht wissen. Zum Beispiel Tree<int> wird nicht funktionieren, weil int destroyEverything nicht haben. Der Compiler wird versuchen, Ihren Code mit int anstelle von T zu schreiben und herausfinden, dass der Code nicht kompiliert. Aber da der Compiler „sieht“ nur die aktuelle CPP und alles, was es enthält, wird es nicht möglich sein, Add-Funktion zu überprüfen, da es in einem separaten CPP ist.

Es wird kein Problem mit

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

in einem separaten cpp implementiert, da der Compiler weiß, dass int die einzig akzeptable Art ist und „auf sich selbst zählen“ kann, wenn er Tree.cpp zu kompilieren bekommt, wird er den Fehler finden.

Andere Tipps

Sind Sie sicher, dass die try / catch etwas damit zu tun hat? Was passiert, wenn man einfach die try und catch Linien auf Kommentar, den Rest des Codes lassen, wie es ist, und baut das?

Es könnte nur sein, dass Sie die Bibliothek sind vermisst, die Tree::add(class Price &) von Ihrer Verbindungslinie definiert.

Update: mit Baum-Funktionen mit einem primitiven Typ führt nicht zu einem Verbindungsfehler. Ich meine Frage im Hinblick auf einige der Dinge, die gesagt wurden aktualisiert.

Wie schon andere gesagt haben Sie die Implementierung von Treee zeigen müssen :: add () und uns sagen, wie Sie es verknüpfen.

Auf einem nicht verwandten Punkt, wenn Sie mit Konstrukten wie:

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

im gesamten Code, verschwenden Sie Ihre Zeit offen. Die Chancen, dass Sie in einem modernen Betriebssystem zu einem Punkt des Speicher Erschöpfung immer sind abgelegen und die Chancen für Sie etwas zu tun, nützlich, nachdem es passiert hat, sind etwa Null. Sie werden viel besser einfach zu sagen:

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

ot möglicherweise:

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

und die Ausnahme in diesem Fall der Handhabung zu vergessen.

Sie schrieb in einem Kommentar:

  

als ich dies aber die Funktion ist Teil von Tree.h, und ich es sind. Die Funktion definiert ist: template void Baum :: hinzufügen (T & newData); Wir nennen es die folgende Art und Weise: priceTree.add (* newPriceNode); während priceTree Baum ist, sind beide in der CPP-Datei in Frage definiert.

statt:

priceTree.add(*newPriceNode);

Versuch:

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

add () nimmt einen Verweis auf einen Knoten, keinen Zeiger auf einen Knoten (entsprechend Ihre Definition von Baum).

Sie bekommen Verknüpfung Fehler, keine Fehler-Compiler. Dies sagt uns, dass der Compiler wußte, welche Art von Funktion Tree::add() ist, aber hatte keine Definition. In Tree.h sehe ich eine Erklärung der add () Funktion, aber keine Definition. Es sieht seltsam für mich; weiß jemand, wo Tree.h kam?

Normalerweise wird eine Template-Klasse kommt mit den Mitgliedsfunktionsdefinitionen in der Include-Datei, da die Funktionen irgendwo instanziiert werden müssen, und die einfachste Sache ist, dass der Compiler bei der Verwendung zu instanziiert und den Linker sortieren lassen Sie es heraus. Wenn die Definitionen in Tree.h sind, würde ich erwarten, dass alles wie geplant funktioniert.

Also, ich werde auf einem Bein gehen und lassen vermuten, dass die Definitionen in einer separaten Datei, nicht verknüpft in, und dass es Vorschriften an anderer Stelle für Grundtypen wie Tree<int> instanziieren. Dies ist vermutlich Kompilierung zu rationalisieren, da normalerweise diese Dinge an mehreren Stellen kompiliert werden, und das braucht Zeit.

Was müssen Sie in diesem Fall zu tun ist, um herauszufinden, wo Tree<int> instanziert wird, und eine Instanziierung für Ihre Klasse hinzuzufügen.

Ich könnte weg sein Basis hier, aber meine Erklärung passt die Fakten, die Sie gegeben haben.

Bearbeiten nach dem ersten Kommentaren :

Vorlagen sind etwas komplizierter als gewöhnliche Funktionen, die in der Regel kein wirkliches Problem ist. Wenn die Definitionen für alle Anrufe in Tree.h, dann wäre Festival.cpp der Lage sein Tree<Band> zu instanziiert und würde alles cool. Das ist die übliche Technik, und Sie laufen in dieses Problem, weil Sie sie nicht verwenden.

Wenn Sie eine Funktion schreiben, wird es kompiliert, und der Linker wird es finden. Jede Routine, die Funktion aufrufen muss den Funktionsprototyp wissen, so wird es wissen, wie es nennen. Wenn Sie eine Vorlage schreiben, bist du nichts zu schreiben, die direkt in das Programm gehen, aber jede Verwendung der Vorlage zählt als alle Funktionen zu schreiben.

Daher hat es einige Verwendung von Tree<Band> in Ihrem Programm irgendwo sein, denn es gibt eine Tree<Band>::add() Funktion kompiliert werden. Die Definition von Tree<T>::add muss den Compiler verfügbar sein, wenn Tree<Band> instanziert wird, weil sonst der Compiler keine Ahnung hat, was zu kompilieren. In diesem Fall ist es die Erzeugung des Funktionsaufrufes, zuversichtlich, dass Sie sicher, würden die Funktion an anderer Stelle kompiliert wird.

Deshalb haben Sie Tree<Band> innerhalb einer Datei zu instanziiert, die sowohl den Zugriff auf die Definitionen für Tree<T> und Band hat. Das bedeutet wahrscheinlich, eine Datei, die ist, oder enthält, Tree.cpp und umfasst Festival.h.

Der Linker verwendet bereits Tree.cpp, aber Tree.cpp nicht über Tree<Band> darin definiert, so ist es an den Linker bedeutungslos. Vorlagen sind für die Compiler nur dann sinnvoll, und der Linker funktioniert nur auf dem, was der Compiler aus Vorlagen erzeugt.

Der schnelle Weg, dies zu lösen, ist die Definition von Tree.cpp zu nehmen und sie in Tree.h. Das wird wahrscheinlich Kompilierung und Verbindungszeiten zu erhöhen, leider. Die andere Technik ist alles Vorlage verwendet in Tree.cpp zu instanziiert, so dass sie dort kompiliert werden werden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top