1

我已经获得了一些我应该修改的源代码(作为作业的一部分),但是我无法编译未经修改的代码版本,而且我正在抓狂。(要清楚 - 此代码用于哈希表上的学校作业,这些编译错误不是作业的一部分)

我正在使用 Visual Studio 2010 进行编译。我整天都在做这件事,却一无所获!

我收到一系列“LNK2005”错误:

1>------ Build started: Project: Assignment10, Configuration: Debug Win32 ------
1>  hashmain.cpp
1>e:\google drive\cpsc 1160\labs\projects\assignment10\assignment10\hashtable.cpp(40): warning C4018: '<' : signed/unsigned mismatch
1>hashtable.obj : error LNK2005: "public: __thiscall HashTableSavitch::HashTable::HashTable(void)" (??0HashTable@HashTableSavitch@@QAE@XZ) already defined in hashmain.obj
1>hashtable.obj : error LNK2005: "public: virtual __thiscall HashTableSavitch::HashTable::~HashTable(void)" (??1HashTable@HashTableSavitch@@UAE@XZ) already defined in hashmain.obj
1>hashtable.obj : error LNK2005: "private: static int __cdecl HashTableSavitch::HashTable::computeHash(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (?computeHash@HashTable@HashTableSavitch@@CAHV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) already defined in hashmain.obj
1>hashtable.obj : error LNK2005: "public: bool __thiscall HashTableSavitch::HashTable::containsString(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)const " (?containsString@HashTable@HashTableSavitch@@QBE_NV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) already defined in hashmain.obj
1>hashtable.obj : error LNK2005: "public: void __thiscall HashTableSavitch::HashTable::put(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (?put@HashTable@HashTableSavitch@@QAEXV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) already defined in hashmain.obj
1>E:\Google Drive\CPSC 1160\Labs\Projects\Assignment10\Debug\Assignment10.exe : fatal error LNK1169: one or more multiply defined symbols found
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

这是给我的代码:

哈希main.cpp

// Program to demonstrate use of the HashTable class

#include <string>
#include <iostream>
#include "listtools.cpp"    // Your compiler may compile separately
#include "hashtable.h"
#include "hashtable.cpp"    // Your compiler may compile separately
using std::string;
using std::cout;
using std::endl;
using HashTableSavitch::HashTable;

int main()
{
    HashTable h;

    cout << "Adding dog, cat, turtle, bird" << endl;
    h.put("dog");
    h.put("cat");
    h.put("turtle");
    h.put("bird");
    cout << "Contains dog? "
        << h.containsString("dog") << endl;
    cout << "Contains cat? "
        << h.containsString("cat") << endl;
    cout << "Contains turtle? "
        << h.containsString("turtle") << endl;
    cout << "Contains bird? "
        << h.containsString("bird") << endl;

    cout << "Contains fish? "
        << h.containsString("fish") << endl;
    cout << "Contains cow? "
        << h.containsString("cow") << endl;

    return 0;
}

哈希表.h

// This is the header file hashtable.h.  This is the interface
// for the class HashTable, which is a class for a hash table
// of strings.

#ifndef HASHTABLE_H
#define HASHTABLE_H

#include <string>
#include "listtools.h"

using LinkedListSavitch::Node;
using std::string;

namespace HashTableSavitch
{
  const int SIZE = 10;

  class HashTable
  {
   public:
        HashTable(); // Initialize empty hash table

        // Normally a copy constructor and overloaded assignment
        // operator would be included.  They have been omitted
        // to save space.

        virtual ~HashTable();  // Destructor destroys hash table

        bool containsString(string target) const;
        // Returns true if target is in the hash table,
        // false otherwise

        void put(string s);
        // Adds a new string to the hash table

   private:
        Node<string> *hashArray[SIZE];
        static int computeHash(string s);   // Compute hash value for string

  }; // HashTable
} // HashTableSavitch
#endif // HASHTABLE_H

哈希表.cpp

// This is the implementation file hashtble.cpp.
// This is the implementation of the class HashTable.

#include <string>
#include "listtools.h"
#include "hashtable.h"

using LinkedListSavitch::Node;
using LinkedListSavitch::search;
using LinkedListSavitch::headInsert;
using std::string;

namespace HashTableSavitch
{
   HashTable::HashTable()
   { 
    for (int i = 0; i < SIZE; i++)
    {
     hashArray[i] = NULL;
    }
   }

   HashTable::~HashTable()
   {
     for (int i=0; i<SIZE; i++)
     {
       Node<string> *next = hashArray[i];
       while (next != NULL)
       {
         Node<string> *discard = next;
     next = next->getLink( );
     delete discard;
       }
     }
   }

   int HashTable::computeHash(string s)
   {
    int hash = 0;
    for (int i = 0; i < s.length( ); i++) 
    {
     hash += s[i];
    }
    return hash % SIZE; 
   }

   bool HashTable::containsString(string target) const
   { 
    int hash = this->computeHash(target);
    Node<string>* result = search(hashArray[hash], target);
    if (result == NULL) 
       return false;
    else
       return true;
   }

   void HashTable::put(string s)
   {
    int hash = computeHash(s);
    if (search(hashArray[hash], s)==NULL)
    {
      // Only add the target if it's not in the list
      headInsert(hashArray[hash], s);
    }
   }

} // HashTableSavitch

列表工具.h

//This is the header file listtools.h. This contains type definitions and
//function declarations for manipulating a linked list to store data of any type T.
//The linked list is given as a pointer of type Node<T>* which points to the 
//head (first) node of the list. The implementation of the functions are given
//in the file listtools.cpp.
#ifndef LISTTOOLS_H
#define LISTTOOLS_H

namespace LinkedListSavitch
{
    template<class T>
    class Node
    {
    public:
        Node(const T& theData, Node<T>* theLink) : data(theData), link(theLink){}
        Node<T>* getLink( ) const { return link; }
        const T& getData( ) const { return data; }
        void setData(const T& theData) { data = theData; }
        void setLink(Node<T>* pointer) { link = pointer; }
    private:
        T data;
        Node<T> *link;
    };

    template<class T>
    void headInsert(Node<T>*& head, const T& theData);
    //Precondition: The pointer variable head points to
    //the head of a linked list.
    //Postcondition: A new node containing theData
    //has been added at the head of the linked list.

    template<class T>
    void insert(Node<T>* afterMe, const T& theData);
    //Precondition: afterMe points to a node in a linked list.
    //Postcondition: A new node containing theData
    //has been added after the node pointed to by afterMe.

    template<class T>
    void deleteNode(Node<T>* before);
    //Precondition: The pointers before point to nodes that has 
    //at least one node after it in the linked list. 
    //Postcondition: The node after the node pointed to by before
    //has been removed from the linked list and its storage 
    //returned to the freestore.

    template<class T>
    void deleteFirstNode(Node<T>*& head);
    //Precondition: The pointers head points to the first
    //node in a linked list; with at least one node.
    //Postcondition: The node pointed to by head has been removed
    //for the linked list and its storage returned to the freestore.

    template<class T>
    Node<T>* search(Node<T>* head, const T& target);
    //Precondition: The pointer head points to the head of a linked list.
    //The pointer variable in the last node is NULL. head (first) node
    //head (first) node has been defined for type T. 
    //(== is used as the criterion for being equal).
    //If the list is empty, then head is NULL.
    //Returns a pointer that points to the first node that 
    //is equal to the target. If no node equals the target, 
    //the function returns NULL.
}//LinkedListSavitch

#endif //LISTTOOLS_H

列表工具.cpp

//This is the implementation file listtools.cpp. This file contains 
//function definitions for the functions declared in listtools.h.

#include <cstddef>
#include "listtools.h"

namespace LinkedListSavitch
{
    template<class T>
    void headInsert(Node<T>*& head, const T& theData)
    {
        head = new Node<T>(theData, head);
    }

    template<class T>
    void insert(Node<T>* afterMe, const T& theData)
    {
        afterMe->setLink(new Node<T>(theData, afterMe->getLink( )));
    }

    template<class T>
    void deleteNode(Node<T>* before)
    {
        Node<T> *discard;
        discard = before->getLink( );
        before->setLink(discard->getLink( ));
        delete discard;
    }

    template<class T>
    void deleteFirstNode(Node<T>*& head)
    {
        Node<T> *discard;
        discard = head;
        head = head->getLink( );
        delete discard;
    }

    //Uses cstddef:
    template<class T>
    Node<T>* search(Node<T>* head, const T& target)
    {
        Node<T>* here = head;

        if (here == NULL) //if empty list
        {
            return NULL;
        }
        else
        {
            while (here->getData( ) != target && here->getLink( ) != NULL)
                here = here->getLink( );

            if (here->getData( ) == target)
                return here;
            else
                return NULL;
        }
    }

}//LinkedListSavitch

我认为这超出了我的深度,我在这里以及在谷歌上可以找到的任何其他地方都倾注了类似的问题/解决方案,但我完全被难住了。

编辑: 根据 Arcinde 的要求,我#include "hashtable.cpp"在 hashmain.cpp 中这样注释掉:

#include <string>
#include <iostream>
#include "listtools.cpp"    // Your compiler may compile separately
#include "hashtable.h"
//#include "hashtable.cpp"  // Your compiler may compile separately
using std::string;
using std::cout;
using std::endl;
using HashTableSavitch::HashTable;

这会产生以下错误:

1>------ Build started: Project: Assignment10, Configuration: Debug Win32 ------
1>  hashmain.cpp
1>hashtable.obj : error LNK2019: unresolved external symbol "class LinkedListSavitch::Node<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > * __cdecl LinkedListSavitch::search<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >(class LinkedListSavitch::Node<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > *,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &)" (??$search@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@LinkedListSavitch@@YAPAV?$Node@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@0@PAV10@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) referenced in function "public: bool __thiscall HashTableSavitch::HashTable::containsString(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)const " (?containsString@HashTable@HashTableSavitch@@QBE_NV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z)
1>hashtable.obj : error LNK2019: unresolved external symbol "void __cdecl LinkedListSavitch::headInsert<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >(class LinkedListSavitch::Node<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > * &,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &)" (??$headInsert@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@LinkedListSavitch@@YAXAAPAV?$Node@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@0@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) referenced in function "public: void __thiscall HashTableSavitch::HashTable::put(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (?put@HashTable@HashTableSavitch@@QAEXV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z)
1>E:\Google Drive\CPSC 1160\Labs\Projects\Assignment10\Debug\Assignment10.exe : fatal error LNK1120: 2 unresolved externals
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
4

3 回答 3

2

看起来你的问题的根源是你在没有实现的情况下实例化模板函数(你的 .h 试图声明,你的 .cpp 试图定义它们)。

您有两种选择来解决您的问题:

  1. 将 listtools.cpp 中的所有内容移动到 listtools.h 中,从而将模板实例化和实现移动到同一个位置
  2. 将 listtools.cpp 中的所有内容移动到新文件 (listtoolssupport.h) 中,并从 listtools.h 中删除声明。

使用选项 1,我使用 @n0rd 和 @Arcinde 的说明将 listtools.cpp 的所有实现移动到 listtools.h 中。然后我完全删除了 listtools.cpp,因为它现在什么都不做,并删除了 .cpp 的#includes。

listtools.h 现在看起来像:

//This is the header file listtools.h. This contains type definitions and
//function declarations for manipulating a linked list to store data of any type T.
//The linked list is given as a pointer of type Node<T>* which points to the 
//head (first) node of the list. The implementation of the functions are given
//in the file listtools.cpp.
#ifndef LISTTOOLS_H
#define LISTTOOLS_H
#include <cstddef>
namespace LinkedListSavitch
{
template<class T>
class Node
{
public:
    Node(const T& theData, Node<T>* theLink) : data(theData), link(theLink) { }
    Node<T>* getLink() const { return link; }
    const T& getData() const { return data; }
    void setData(const T& theData) { data = theData; }
    void setLink(Node<T>* pointer) { link = pointer; }
private:
    T data;
    Node<T> *link;
};

template<class T>
void headInsert(Node<T>*& head, const T& theData)
{
    head = new Node<T>(theData, head);
}
//Precondition: The pointer variable head points to
//the head of a linked list.
//Postcondition: A new node containing theData
//has been added at the head of the linked list.

etc etc etc...

“未解析的外部符号”基本上是说,当它去链接时,它找不到 Node 的符号。

于 2015-07-24T23:59:18.470 回答
-1

在你的hashmain.cpp文件中

// Program to demonstrate use of the HashTable class

#include <string>
#include <iostream>
//#include "listtools.cpp"  // Your compiler may compile separately
#include "hashtable.h"
//#include "hashtable.cpp"  // Your compiler may compile separately
using std::string;
using std::cout;
using std::endl;
using HashTableSavitch::HashTable;

尝试取消注释两个注释行。

于 2015-07-25T00:02:29.137 回答
-1

包含源代码文件名是错误的,所以你应该注释掉它们。

于 2015-07-26T10:40:08.753 回答