6

私が書いたクラスから、いくつかの非常に奇妙なリンク エラーが発生しています。何が起こっているのかを説明するものを完全に見つけることができません。

ビジュアル スタジオ (Windows XP)

Players.obj : エラー LNK2019: 未解決の外部シンボル "public: __thiscall TreeNode::TreeNode(void)" (??0?$TreeNode@VPlayer@@@@QAE@XZ) が関数 "public: __thiscall PlayerList::PlayerList で参照されています(無効)" (??0PlayerList@@QAE@XZ)

エクスコード (OSX 10.5)

未定義のシンボル: "TreeNode::~TreeNode()"、参照元: PlayerList::~PlayerList() inplayers.o

ヘッダー ファイル: 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;
};

TreeNode のサブクラスからのコード

PlayerList::PlayerList() : TreeNode<Player>(){}
PlayerList::PlayerList(istream &in) : TreeNode<Player>(in){}
PlayerList::~PlayerList(){}
4

4 に答える 4

15

テンプレートを .cpp ファイルで定義するときは、事前に次のようにテンプレートが使用されることがわかっているすべての型/テンプレート パラメーターを使用して明示的にインスタンス化する必要があります (.cpp ファイルに入れます)。

template class TreeNode<Player>;

テンプレートが使用されるテンプレート パラメーターがわからない場合は、すべての定義をヘッダーに配置する必要があります。お気に入り

template<typename T>
class TreeNode {
public:
   TreeNode() /* now, also put the code into here: */ { doSomething(); }
};

その理由は、どこかからテンプレートを使用する場合、コンパイラはテンプレートの特定のインスタンス化のためのコードを生成できなければならないからです。ただし、コードを .cpp ファイルに配置してコンパイルすると、コンパイラがコードを取得してインスタンス化を生成する方法はありません (悪名高いexportキーワードを使用する場合を除きます。これは、非常に少数のコンパイラでしかサポートされていません)。 .

これは、私の C++ の落とし穴の回答のエントリでもあります。どの C++ の落とし穴を避けるべきですか?

于 2008-11-23T11:18:01.043 に答える
2

~TreeNode() を宣言していますが、それを定義していますか?

デストラクタを宣言すると、コンパイラによるデストラクタの生成が停止されますが、空であってもどこかに定義する必要があります。

意図が空のデストラクタを持つことであった場合、次の 2 つのオプションがあります。

- ~TreeNode() の宣言を完全に削除し、自己生成のデストラクタに依存します - 空として定義します。Inling はここでとてもいいでしょう、IE。~TreeNode() {};

于 2008-11-23T04:53:49.227 に答える
1

コンパイラは、デストラクタの実装が見つからないと不平を言っています。前に指摘したように、デストラクタを宣言しても、コンパイラは自動的にデストラクタを生成しません。

空のデストラクタを削除または提供するというDavid Reisの提案に対して、私は明らかに 2 番目の方法を選択します。クラスが派生することを意図している (仮想メソッドがある)場合は、空であっても仮想デストラクタを提供する必要があります (同じことが BaseNode にも当てはまります)。

コンパイラで生成されたバージョンに依存していて、コンストラクターが仮想ではない基本クラスへのポインターを介してユーザー コードが派生オブジェクトを削除する場合、派生オブジェクトのデストラクターは呼び出されず、リソースがリークする可能性があります。

于 2008-11-23T10:33:01.837 に答える
0

クラス関数の関数本体を含むオブジェクト ファイルをリンクするのを忘れていませんか?

たとえば、.cpp には次のようなものがあります。

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

TreeNode::~TreeNode()
{
    // ...
}
于 2008-11-23T04:44:44.037 に答える