2011-11-15 49 views
0

可能重複:
Why can templates only be implemented in the header file?麻煩與單鏈表實現模板

我有一個單向鏈表按字母順序插入新的書名,並刪除它們。我現在試圖將其轉換爲模板程序,以便可以使用除Book之外的其他對象。我已經經歷了所有錯誤的工作,但在構建具有以下我仍然失敗:

Undefined symbols for architecture x86_64: 
    "ObjectList<Book>::insert(Book*)", referenced from: 
     _main in lib.o ,br> 
    "ObjectList<Book>::getObjectList(char*)", referenced from: 
     _main in lib.o 
    "ObjectList<Book>::delet(Book*)", referenced from: 
     _main in lib.o 

我不太知道我做錯了所以這裏是代碼:

//-------------------------------------------------------------- 
// lib.cpp 
// 
//-------------------------------------------------------------- 

#include <iostream> 
using namespace std; 
#include "ObjectList.h" 
#include "Book.h" 

int main(int argc, char* argv[]) { 
//-------------------------------------------------------------- 
// Creates a BookList object, adds several books to the list, 
// then prints them. 
//-------------------------------------------------------------- 

    char list[2048]; 
    ObjectList<Book> *books = new ObjectList<Book>(); 

    books->insert (new Book("F Title")); 
    books->insert (new Book("D Title")); 
    books->insert (new Book("G Title")); 
    books->insert (new Book("A Title")); 
    books->insert (new Book("E Title")); 
    books->insert (new Book("H Title")); 

    cout << "After inserts:\n"; 
    cout << books->getObjectList(list) << endl;; 
//*/ 
    books->delet (new Book("A Title")); 
    books->delet (new Book("H Title")); 
    books->delet (new Book("G Title")); 
    books->delet (new Book("E Title")); 

    cout << "After deletes:\n"; 
    cout << books->getObjectList(list) << endl;; 

    books->insert (new Book("A Title")); 
    books->insert (new Book("E Title")); 
    books->insert (new Book("H Title")); 
    books->insert (new Book("G Title")); 

    cout << "After 2nd inserts:\n"; 
    cout << books->getObjectList(list) << endl;; 
//*/ 
    return 0; 
} 

/* /當成功運行,這應該是輸出:

後插入:
A標題
d標題
Ë標題
˚F標題
克標題
ħ標題

後刪除:
d標題
˚F標題

第二插入件後:
A標題
d標題
Ë標題
˚F標題
G標題
當它不使用模板^ h標題

ObjectList.h

//******************************************************************** 
// ObjectListt.h 
// 
// Represents a collection of books. 
//******************************************************************* 

#include <iostream> 
using namespace std; 

template<class T> 
class ObjectNode { 
    public: 
     //-------------------------------------------------------------- 
     // Sets up the node 
     //-------------------------------------------------------------- 
     ObjectNode() {} 
     ObjectNode(T *theObject) { 
     object = theObject; 
     next = NULL; 
     } 
     friend class ObjectList; 

    private: 
     T *object; 
     ObjectNode *next; 
}; 

template<class T> 
class ObjectList { 

    //---------------------------------------------------------------- 
    // Sets up an empty list of books. 
    //---------------------------------------------------------------- 
    public: 
     void add(T *); 
     void insert(T *); 
     void delet(T *); 
     char* getObjectList(char *); 

     ObjectList() { 
     head = NULL; 
     } 

    private: 
     ObjectNode<T> *head; 

}; 

Book.h

#include <cstring> 
#include <iostream> 
using namespace std; 

//******************************************************************** 
// Book.h 
// 
// Represents a single book. 
//******************************************************************* 

class Book { 

    public: 
     Book (char *newTitle) { 
     strcpy(title, newTitle); 
     } 

     int compareTo(Book *test_book) 
     { 
      // comparing test_book to this book 
      int comparison; 

      comparison = strcmp(test_book->getObject(), title); 

      return comparison; 
     } 
//*/ 
     char *getObject() { 
     return title; 
     } 

    private: 
     char title[81]; 

    }; 

這個程序工作得很好。我沒有包含ObjectList.cpp的代碼,因爲它大約有160行,並不認爲包含它是完全必要的。讓我知道你是否需要看到它。

任何數量的幫助表示讚賞這個最有可能的菜鳥錯誤。

硬件信息: 2011 15" MacBook Pro的運行OS X Lion的 NetBeans IDE的所有更新

+0

模板ObjectList類的所有方法的實現必須在頭文件(或者當你使用'ObjectList '類時至少包含某種方式) – Mat

+3

有什麼理由不使用'std :: list <>'? –

+0

我打算建議一個std :: list,但是這個行爲更像是一個std :: set,因爲這些書籍是按照字母順序存儲的。 – Joel

回答

4

想必你有,在ObjectList.cpp

template <typename T> void ObjectList<T>::insert(T *) 
{ // ... 
} 

右好了,問題的定義是什麼?如果不知道傳入的值爲T,編譯器無法生成代碼,這通常意味着調用該方法的位置。

如果您將所有方法體模板化的類內聯(進入標題),它會工作。這是編寫C++模板的常用方式:它全部存在於頭文件中。

+3

那麼,你可以將實現移動到單獨的文件中,但是你仍然必須將它包含在頭文件中,或者導出顯式實例。 –

+0

+1。只需在頭中添加ObjectList成員函數的實現。您可以將該實現與聲明一起內聯,或聲明您的類並定義實現,但由於ObjectList是模板類,因此它必須全部位於標題中。 – Joel

1

編譯器必須有權訪問模板函數的定義,以便爲給定值T生成適當的實現。在頭文件中定義了習慣上的模板函數。他們可以在其他地方定義,但無論您在哪裏使用它們,都需要包含該文件。最好只是把它全部放在標題中。

0

重命名ObjectList.cpp到ObjectList.tpp和ObjectList.h的最底部加入這一行

#include "ObjectList.tpp" 

這是一個黑客工具,讓您保持您的實現在一個單獨的文件,還可以確保包含頭文件的任何人也可以獲得實現(因爲模板系統需要這樣的東西)。

這裏有其他事情的清單,你會想看看:

  1. 你會想要確保你new也將傳遞到delete任何對象。
  2. 使用頭文件包含守護是一個好主意(只要確保我上面提到的#include是INSERT在ObjectList.h中的包含守衛)。
  3. 避免strcpy像瘟疫一樣。這很難正確使用。您應該更喜歡使用<string>頭文件中的類和函數(除非您有非特定的原因不這樣做,即性能)