在单链表上实现模板的问题

Trouble with Implementing Templates on a Singly Linked List

本文关键字:实现 问题 单链表 链表      更新时间:2023-10-16

可能重复:
为什么模板只能在头文件中实现?

我有一个单独链接的列表,可以按字母顺序插入新书标题,也可以删除它们。我现在正试图将其转换为一个模板程序,以便可以使用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;
}

/*/当成功运行时,这应该是输出:

插入后:
标题
D标题
E标题
F标题
G标题
H标题

删除后:
D标题
F标题

第二次插入后:
标题
D标题
E标题
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 LionNetbeans IDE与所有更新

假设您在ObjectList.cpp中有的定义

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

对吧?好吧,问题是编译器不能在不知道作为t传递的值的情况下生成代码,t通常意味着方法的调用位置。

如果将模板化类的所有方法体内联(移动到头中(,它就会起作用。这是编写C++模板的常用方法:它都存在于头中。

编译器必须能够访问模板函数的定义,以便为给定的T值生成适当的实现。特有的模板函数在头文件中定义。它们可以在其他地方定义,但无论在哪里使用,都需要包含该文件。最好把所有的东西都放在头上。

将ObjectList.cpp重命名为ObjectList.tpp,并在ObjectList.h 的最底部添加此行

#include "ObjectList.tpp"

这是一种破解方法,它允许您将实现保存在一个单独的文件中,同时确保任何包含头文件的人也能获得实现(因为模板系统需要这样的东西(。

以下是您想要查看的其他内容的列表:

  1. 您需要确保new的任何对象也传递给delete
  2. 使用头包含保护是一个好主意(只需确保我上面提到的#include位于ObjectList.h中的包含保护内部(
  3. 像躲避瘟疫一样躲避strcpy。它很难正确使用。您应该更喜欢使用<string>头文件中的类和函数(除非您有非常具体的原因,例如性能(