C++ C++;链接错误:使用模板类的未定义符号

C++ C++;链接错误:使用模板类的未定义符号,c++,linker,C++,Linker,我从我写的一个类中得到了一些非常奇怪的链接错误。我完全找不到任何能够描述正在发生的事情的东西 Visual Studio(Windows XP) players.obj:错误LNK2019:未解析的外部符号“public:u thiscall TreeNode::TreeNode(void)”(?0$TreeNode@VPlayer@@@@QAE@XZ)在函数“public:u thiscall PlayerList::PlayerList(void)”中引用(??0 PlayerList@@Q

我从我写的一个类中得到了一些非常奇怪的链接错误。我完全找不到任何能够描述正在发生的事情的东西

Visual Studio(Windows XP)

players.obj:错误LNK2019:未解析的外部符号“public:u thiscall TreeNode::TreeNode(void)”(?0$TreeNode@VPlayer@@@@QAE@XZ)在函数“public:u thiscall PlayerList::PlayerList(void)”中引用(??0 PlayerList@@QAE@XZ)

Xcode(OSX 10.5)

未定义的符号:“TreeNode::~TreeNode()”,引用自:PlayerList::~PlayerList()

头文件:generics.h

class TreeNode : public BaseNode{
public:
    const static int MAX_SIZE = -1; //-1 means any size allowed. 
    const static int MIN_SIZE = 0;
    //getters
    int size() const;
    vector<C*> getChildren() const;
    //setters
    void setChildren(vector<C*> &list);
    //Serialization
    virtual void display(ostream &out) const;
    virtual void read(istream &in);
    virtual void write(ostream &out) const;
    //Overrides so SC acts like an array of sorts. 
    virtual C* get(int id) const; 
    virtual int get(C *child) const;
    virtual bool has(C *child) const;
    virtual C* pop(int id);
    virtual void push(C *child);
    virtual TreeNode& operator<< (C *child); //append
    virtual void remove(int id); //Clears memory 
    virtual void remove(C *child); //Clears memory 
    //Initalizers
    TreeNode();
    TreeNode(istream &in);
    TreeNode(long id, istream &in);
    TreeNode(BaseNode* parent, istream &in);
    TreeNode(long id, BaseNode* parent);
    TreeNode(long id, BaseNode* parent, istream &in);
    ~TreeNode();
    string __name__() const{ return "TreeNode"; }
protected:
    void clearChildren();
    void initalizeChildren();
    vector<C*> _children;
};
类树节点:公共基节点{
公众:
const static int MAX_SIZE=-1;/-1表示允许的任何大小。
const static int MIN_SIZE=0;
//吸气剂
int size()常量;
向量getChildren()常量;
//二传手
无效设置子项(向量和列表);
//系列化
虚拟空隙显示(ostream&out)常数;
虚拟无效读取(istream&in);
虚空写入(ostream&out)常数;
//重写,使SC的行为类似于排序数组。
虚拟C*get(int-id)常量;
虚拟整数get(C*子)常量;
虚拟布尔具有(C*子)常量;
虚拟C*pop(int-id);
虚拟无效推送(C*子级);

virtual TreeNode&operator您是否忘记链接包含类函数的函数体的对象文件

例如,在.cpp中,您可能会遇到类似的情况:

TreeNode::TreeNode() :
    /* initializers here */
{
    // ...
}

TreeNode::~TreeNode()
{
    // ...
}

您正在声明~TreeNode(),但您正在定义它吗

当您声明析构函数时,您会阻止编译器为您生成析构函数,但您必须在某个地方定义它,即使它是空的

如果您打算使用空析构函数,则有两种选择:

-完全删除~TreeNode()的声明,并依赖自生成的析构函数
-将其定义为空。在这里内联将非常好,即~TreeNode(){};

编译器正在抱怨找不到析构函数的实现。如前所述,如果您声明析构函数,编译器将不会自动为您生成一个

对于删除或提供空析构函数的建议,我显然会选择第二个。如果您的类是要派生的(您有虚拟方法),那么您应该提供虚拟析构函数,即使它是空的(同样适用于BaseNode)


如果依赖于编译器生成的版本,并且用户代码通过指向构造函数不是虚拟的基类的指针删除派生对象,则不会调用派生对象的析构函数,这可能会泄漏资源。

在.cpp文件中定义模板时,必须使用所有类型显式实例化它s/template参数已知模板将提前使用,如下所示(将其放入.cpp文件中):

模板类树节点;
如果您不知道该模板将与哪些模板参数一起使用,则必须将所有定义放入标题中

template<typename T>
class TreeNode {
public:
   TreeNode() /* now, also put the code into here: */ { doSomething(); }
};
模板
三烯类{
公众:
TreeNode()/*现在,将代码放在这里:/{doSomething();}
};

原因是,当您打算从某个地方使用模板时,编译器必须能够为该模板的特定实例化生成代码。但是,如果您将代码放入.cpp文件并进行编译,编译器将无法获得生成实例化的代码(使用声名狼藉的
export
关键字时除外,只有极少数编译器支持该关键字)


<>这也是我的C++陷阱中的一个条目:

TreeNode定义的代码::~(TeReNODE)?“编译器无法掌握代码来生成实例化。”除非你使用CeMueC++,其中链接器能够模板实例化。技术可能会到达主流编译器,有一天,就不是今天……呵呵:让我们一整天都保持乐观顺便说一句,英特尔编译器也支持这一点,凭借其优秀的爱迪生设计团队前端。我不是说你错了,只是有一线希望:-)一个接一个,不,我没有那样对待它。一切都很好。如果我听起来有点刺耳,我很抱歉:)缺失
{
,在我的构造器后面,谢谢!
template class TreeNode<Player>;
template<typename T>
class TreeNode {
public:
   TreeNode() /* now, also put the code into here: */ { doSomething(); }
};