我收到以下类型的链接错误:

  

Festival.obj:错误LNK2019:   未解析的外部符号<!> quot; public:   void __thiscall Tree :: add(class Price <!> amp;)<!> quot;   (?添加@?$ @树@@@@ VPrice @@@ QAEXAAVPrice Z)   在函数中引用   __catch $?AddBand @ @@节QAE?AW4StatusType @@ @ HHH Z $ 0

我曾经认为它与try-catch机制有关,但是从那以后就被告知了。这是该问题的更新版本。

我正在使用Visual Studio 2008,但我在g ++中遇到了类似的问题。

相关代码:

在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);
....
}

在Tree.h中:

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

有趣的是,当我尝试使用Tree函数时,我没有链接错误,当类型T是像int这样的基本类型时。

有帮助吗?

解决方案

有Tree.cpp吗?如果有,也许你忘了链接它? Tree :: add的实现在哪里? 另外我看不到你在哪里调用Tree :: add。我想它应该在try语句中,就在新的?

之后

提醒一下:

对于大多数编译器(即那些进行单独编译的编译器),在编译使用模板类的源文件时,必须能够看到模板类的成员函数的实现。通常人们通过将成员函数的实现放在头文件中来遵循这个规则。

也许Tree :: add不在标题内?然后在讨论的案例中可能的解决方案是将Tree :: add实现放在头文件中。

常规类和模板类之间存在差异,因为模板类不是<!>“真实的<!>”;类 - 它是一个模板。如果您已将Tree类定义为常规类,则编译器可能已立即使用您的代码。在模板的情况下,编译器首先<!> quot;写<!> quot;为您提供真正的类,用您提供的类型替换模板参数。现在,编译器逐个编译cpp文件。他不知道其他cpp文件,并且不能使用其他cpp文件。假设您实现Tree:添加如下所示:

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

只要你的T有方法destroyEverything,这是完全合法的。当编译器编译Class.cpp时,它希望确保你不会使用它不知道的任何东西。例如Tree<int>将无法工作,因为int没有destroyEverything。编译器将尝试使用int而不是T编写代码,并发现代码无法编译。但是因为编译器<!>“看到了<!>”;只有当前的cpp及其包含的所有内容,它将无法验证添加功能,因为它位于单独的cpp中。

不会有任何问题
void Tree::add(int& newData)
{
    newData.destroyEverything();
}

在一个单独的cpp中实现,因为编译器知道int是唯一可接受的类型,并且可以<!>“依靠自己<!>”;当他编译Tree.cpp时,他会发现错误。

其他提示

你确定try / catch与它有关吗?如果您只是注释掉Tree::add(class Price &)和<=>行,将其余代码保留原样并构建它,会发生什么?

可能只是因为您错过了从链接行定义<=>的库。

更新:使用具有基本类型的树函数不会导致链接错误。 我根据所说的一些事情更新了我的问题。

正如其他人所说,你需要展示Treee :: add()的实现,并告诉我们你是如何链接它的。

在一个不相关的点上,如果你使用的结构如下:

  Band* newBand=NULL;
    try{
        newBand=new Band(bandID,price-priceOffset,votes);
    }
    catch(bad_alloc&){return ALLOCATION_ERROR;}
在整个代码中,你坦率地浪费你的时间。在现代操作系统中,你达到内存耗尽的可能性是很小的,你在事情发生之后做任何有用的机会大致为零。简单地说,你会好得多:

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

可能:

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

并且在这种情况下忘记了异常处理。

您在评论中写道:

  

我考虑过这个,但函数是Tree.h的一部分,我确实包含了它。定义的函数是:template void Tree :: add(T <!> amp; newData);我们用以下方式调用它:priceTree.add(* newPriceNode);而priceTree是Tree,两者都在相关的cpp文件中定义。

而不是:

priceTree.add(*newPriceNode);

尝试:

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

add()接受对节点的引用,而不是指向节点的指针(根据您对Tree的定义)。

您遇到了链接错误,而不是编译器错误。这告诉我们编译器知道Tree::add()是什么类型的函数,但是没有定义。在Tree.h中,我看到了add()函数的声明,但没有定义。这对我来说很奇怪;有谁知道Tree.h来自哪里?

通常模板类在include文件中带有成员函数定义,因为函数必须在某处实例化,最简单的事情是编译器在使用时实例化并让链接器对其进行排序。如果定义在Tree.h中,我希望一切按计划运行。

所以,我将要讨论这些定义是在一个单独的文件中,没有链接,并且在其他地方有规定实例化基本类型,如Tree<int>。这可能是为了简化编译,因为通常这些东西是在多个地方编译的,这需要时间。

在这种情况下,您需要做的是找到实例化Tree<Band>的位置,并为您的类添加实例化。

我可能会离开这里,但我的解释确实符合你给出的事实。

首次评论后修改

模板比普通函数更棘手,通常不是真正的问题。如果所有调用的定义都在Tree.h中,那么Festival.cpp将能够实例化Tree<Band>::add(),一切都会很酷。这是通常的技术,你遇到了这个问题,因为你没有使用它。

当你编写一个函数时,它会被编译,链接器会找到它。任何调用该函数的例程都需要知道函数原型,因此它将知道如何调用它。当你编写一个模板时,你不会写任何直接进入程序的东西,但任何对模板的使用都算作编写所有函数。

因此,必须在程序中的某处使用Tree<T>::add,以便编译Tree<T>函数。当实例化Band时,编译器必须可以使用<=>的定义,因为否则编译器不知道要编译什么。在这种情况下,它正在生成函数调用,相信您将确保该函数在其他地方编译。

因此,您必须在有权访问<=>和<=>的定义的文件中实例化<=>。这可能意味着一个包含Tree.cpp的文件,包括Festival.h。

链接器已经在使用Tree.cpp,但Tree.cpp中没有定义<=>,因此它对链接器没有意义。模板仅对编译器有用,链接器仅对编译器从模板生成的内容进行操作。

解决这个问题的快捷方法是从Tree.cpp中获取定义并将它们放在Tree.h中。不幸的是,这可能会增加编译和链接时间。另一种技术是在Tree.cpp中实例化所有模板使用,以便在那里编译它们。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top