C++ 抛接球会导致连接错误
我得到了以下类型的链接错误: Festival.obj:错误LNK2019: 未解析的外部符号“公共: void _u此调用树::添加(类价格&)” (?添加@$Tree@VPrice@@@@QaexavPrice@@@Z) 在函数中引用 __捕获$?AddBand@Festival@@QAE?AW4StatusType@@HHH@Z0美元 我过去认为这与试捕机制有关,但后来有人告诉我不是这样。这是问题的更新版本 我使用的是VisualStudio2008,但在g++中也有类似的问题 有关守则: 在Festival.cpp中C++ 抛接球会导致连接错误,c++,visual-studio-2008,templates,try-catch,linker-errors,C++,Visual Studio 2008,Templates,Try Catch,Linker Errors,我得到了以下类型的链接错误: Festival.obj:错误LNK2019: 未解析的外部符号“公共: void _u此调用树::添加(类价格&)” (?添加@$Tree@VPrice@@@@QaexavPrice@@@Z) 在函数中引用 __捕获$?AddBand@Festival@@QAE?AW4StatusType@@HHH@Z0美元 我过去认为这与试捕机制有关,但后来有人告诉我不是这样。这是问题的更新版本 我使用的是VisualStudio2008,但在g++中也有类似的问题 有关守则:
#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”
#包括
使用名称空间std;
班级乐队{
公众:
Band(intbandid,intprice,intvoces=0):bandID(bandID),price(price),voces(voces){};
...
私人:
...
};
班级节{
公众:
节日(int预算):预算(预算),最小价格(0),最大需要预算(0),价格偏移(0),带计数器(0){};
~Festival();
StatusType AddBand(int-bandID、int-price、int-Voces=0);
...
私人:
树带树;
...
};
StatusType Festival::AddBand(整数bandID、整数价格、整数投票){
如果((price您确定try
/catch
与此有关吗?如果您只是注释掉try
和catch
行,将其余代码保持原样,然后构建它,会发生什么
这可能只是因为您缺少从链接行定义Tree::add(class Price&)
的库。更新:将树函数与基元类型一起使用不会导致链接错误。
我根据所说的一些事情更新了我的问题。有Tree.cpp吗?如果有,可能您忘记链接了?Tree::add的实现在哪里?
此外,我看不出您在哪里调用Tree::add。我想它应该在try语句中,就在new之后
只是提醒一下:
对于大多数编译器(即进行单独编译的编译器),在编译使用模板类的源文件期间,模板类的成员函数的实现必须可见。通常,人们遵循这一规则,将成员函数的实现放在头文件中
也许Tree::add不在头文件中?那么在讨论的案例中,一个可能的解决方案是将Tree::add实现放在头文件中
常规类和模板类之间存在差异,因为模板类不是“真实”类-它是一个模板。如果您将树类定义为常规类,编译器可能会立即使用您的代码。对于模板,编译器首先“编写”对于真正的类,请使用您提供的类型替换模板参数。现在,编译器逐个编译cpp文件。他不知道其他cpp文件,并且无法使用其他cpp文件中的任何内容。假设Tree:add的实现如下所示:
void Tree::add(T& newData)
{
newData.destroyEverything();
}
只要你的T方法销毁了所有东西,这是完全合法的。当编译器编译Class.cpp时,它希望确保你不处理它不知道的任何东西。例如,Tree
将不起作用,因为int没有销毁所有东西。编译器将尝试用int而不是T编写你的代码,并发现这一点代码不会编译。但由于编译器只“看到”当前cpp及其包含的所有内容,因此无法验证add函数,因为它位于单独的cpp中
这不会有任何问题
void Tree::add(int& newData)
{
newData.destroyEverything();
}
在一个单独的cpp中实现,因为编译器知道int是唯一可接受的类型,并且可以“依靠自己”在编译Tree.cpp时找到错误。您得到的是链接错误,而不是编译器错误。这告诉我们编译器知道什么类型的函数Tree::add()
是,但没有定义。在Tree.h中,我看到了add()函数的声明,但没有定义。我觉得很奇怪;有人知道Tree.h来自哪里吗
通常模板类在include文件中带有成员函数定义,因为函数必须在某处实例化,最简单的事情是编译器在使用时实例化,并让链接器对其进行排序。如果定义在Tree.h中,我希望一切都按计划进行
因此,我要冒险指出,这些定义是在一个单独的文件中,而不是链接进来的,并且其他地方有一些规定可以实例化基本类型,如树
。这大概是为了简化编译,因为通常这些东西是在多个地方编译的,这需要时间
在这种情况下,您需要做的是找到实例化树的位置,并为类添加一个实例化
我在这里可能有点离谱,但我的解释确实符合你给出的事实
在第一次评论后编辑:
模板比普通函数要复杂一些,这通常不是一个真正的问题。如果所有调用的定义都在Tree.h中,那么Festival.cpp将能够实例化Tree
,一切都会很酷。这是通常的技术,您遇到这个问题是因为您没有使用它
当你编写一个函数时,它会被编译,链接器会找到它。任何调用该函数的例程都需要知道函数原型,这样它就会知道如何调用它。当你编写一个模板时,你不会编写任何将直接进入程序的内容,但是任何使用模板的行为都会被视为编写所有函数
因此,必须在程序的某个地方使用Tree
,才能编译Tree::add()
函数。在实例化Tree
时,编译器必须能够使用Tree::add
的定义,否则编译器就不知道要编译什么
void Tree::add(int& newData)
{
newData.destroyEverything();
}
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 );
priceTree.add(*newPriceNode);
priceTree.add(newPriceNode); //no "*" before "newPriceNode"