双重链接列表:未解决的外部

Doubly Linked List : Unresolved Externals

本文关键字:未解决 外部 列表 链接      更新时间:2023-10-16

可能的重复:
为什么模板只能在头文件中实现
什么是未定义的引用/未解决的外部符号错误?如何修复?

同样,这是一项家庭作业,我的导师给了我们很多反馈,但我仍然对这个编译问题不知所措。

当我把主函数放在实现文件中时,程序会编译并完美工作。然而,当我将主函数放入main.cpp时,编译器会抱怨:

unresolved external symbol "public: __thiscall doublyLinkedList<int>::doublyLinkedList<int>(void)" (??0?$doublyLinkedList@H@@QAE@XZ) referenced in function

标题文件

#ifndef H_doublyLinkedList
#define H_doublyLinkedList
#include <iostream>
#include <cassert>
using namespace std;
//Definition of the node
template <class Type>
struct nodeType
{  
Type info;
nodeType<Type> *next;
nodeType<Type> *back;  
};
template <class Type>
class doublyLinkedList
{
public:
const doublyLinkedList<Type>& operator=
(const doublyLinkedList<Type> &);
//Overload the assignment operator.
void initializeList();
//Function to initialize the list to an empty state.
//Postcondition: first = NULL; last = NULL; count = 0;
bool isEmptyList() const;
//Function to determine whether the list is empty.
//Postcondition: Returns true if the list is empty,
//               otherwise returns false.
void destroy();
//Function to delete all the nodes from the list.
//Postcondition: first = NULL; last = NULL; count = 0;
void print() const;
//Function to output the info contained in each node.
void reversePrint() const;
//Function to output the info contained in each node
//in reverse order.
int length() const;
//Function to return the number of nodes in the list.
//Postcondition: The value of count is returned.
Type front() const;
//Function to return the first element of the list.
//Precondition: The list must exist and must not be empty.
//Postcondition: If the list is empty, the program 
//               terminates; otherwise, the first 
//               element of the list is returned. 
Type back() const;
//Function to return the last element of the list.
//Precondition: The list must exist and must not be empty.
//Postcondition: If the list is empty, the program
//               terminates; otherwise, the last
//               element of the list is returned. 
bool search(const Type& searchItem) const;
//Function to determine whether searchItem is in the list.
//Postcondition: Returns true if searchItem is found in
//               the list, otherwise returns false.
void insert(const Type& insertItem);
//Function to insert insertItem in the list.
//Precondition: If the list is nonempty, it must be in
//              order.
//Postcondition: insertItem is inserted at the proper place
//               in the list, first points to the first
//               node, last points to the last node of the
//               new list, and count is incremented by 1.
void deleteNode(const Type& deleteItem);
//Function to delete deleteItem from the list. 
//Postcondition: If found, the node containing deleteItem
//               is deleted from the list; first points
//               to the first node of the new list, last
//               points to the last node of the new list,
//               and count is decremented by 1; otherwise,
//               an appropriate message is printed. 
doublyLinkedList(); 
//default constructor
//Initializes the list to an empty state.
//Postcondition: first = NULL; last = NULL; count = 0;
doublyLinkedList(const doublyLinkedList<Type>& otherList); 
//copy constructor
~doublyLinkedList(); 
//destructor
//Postcondition: The list object is destroyed.
public:
int count;
nodeType<Type> *first; //pointer to the first node
nodeType<Type> *last;  //pointer to the last node
public:
void copyList(const doublyLinkedList<Type>& otherList); 
//Function to make a copy of otherList.
//Postcondition: A copy of otherList is created and
//               assigned to this list.
};

#endif

实施文件:

#include <iostream>
#include <cassert>
#include "doublyLinkedList.h"
using namespace std;

template <class Type>
doublyLinkedList<Type>::doublyLinkedList()
{
first= NULL;
last = NULL;
count = 0;
}
template <class Type>
bool doublyLinkedList<Type>::isEmptyList() const
{
return (first == NULL);
}
template <class Type>
void doublyLinkedList<Type>::destroy()
{  
nodeType<Type>  *temp; //pointer to delete the node
while (first != NULL)
{
temp = first;
first = first->next;
delete temp;
}
last = NULL;
count = 0;
}
template <class Type>
void doublyLinkedList<Type>::initializeList()
{
destroy();
}
template <class Type>
int doublyLinkedList<Type>::length() const
{
return count;
}
template <class Type>
void doublyLinkedList<Type>::print() const
{
nodeType<Type> *current; //pointer to traverse the list
current = first;  //set current to point to the first node
while (current != NULL)
{
cout << current->info << "  ";  //output info
current = current->next;
}//end while
}//end print

template <class Type>
void doublyLinkedList<Type>::reversePrint() const
{
nodeType<Type> *current; //pointer to traverse 
//the list
current = last;  //set current to point to the 
//last node
while (current != NULL)
{
cout << current->info << "  ";  
current = current->back;
}//end while
}//end reversePrint
template <class Type>
bool doublyLinkedList<Type>::
search(const Type& searchItem) const
{
bool found = false;
nodeType<Type> *current; //pointer to traverse the list
current = first;
while (current != NULL && !found)
if (current->info >= searchItem)
found = true;
else
current = current->next;
if (found)
found = (current->info == searchItem); //test for 
//equality
return found;
}//end search
template <class Type>
Type doublyLinkedList<Type>::front() const
{
assert(first != NULL);
return first->info;
}
template <class Type>
Type doublyLinkedList<Type>::back() const
{
assert(last != NULL);
return last->info;
}
template <class Type>
void doublyLinkedList<Type>::insert(const Type& insertItem)
{
nodeType<Type> *current;      //pointer to traverse the list
nodeType<Type> *trailCurrent; //pointer just before current
nodeType<Type> *newNode;      //pointer to create a node
bool found;
newNode = new nodeType<Type>; //create the node
newNode->info = insertItem;  //store the new item in the node
newNode->next = NULL;
newNode->back = NULL;
if(first == NULL) //if the list is empty, newNode is 
//the only node
{
first = newNode;
last = newNode;
count++;
}
else
{
found = false;
current = first;
while (current != NULL && !found) //search the list
if (current->info >= insertItem)
found = true;
else
{
trailCurrent = current;
current = current->next;
}
if (current == first) //insert newNode before first
{
first->back = newNode;
newNode->next = first;
first = newNode;
count++;
}
else
{
//insert newNode between trailCurrent and current
if (current != NULL)
{
trailCurrent->next = newNode;
newNode->back = trailCurrent;
newNode->next = current;
current->back = newNode;
}
else
{
trailCurrent->next = newNode;
newNode->back = trailCurrent;
last = newNode;
}
count++;
}//end else
}//end else
}//end insert
template <class Type>
void doublyLinkedList<Type>::deleteNode(const Type& deleteItem)
{
nodeType<Type> *current; //pointer to traverse the list
nodeType<Type> *trailCurrent; //pointer just before current
bool found;
if (first == NULL)
cout << "Cannot delete from an empty list." << endl;
else if (first->info == deleteItem) //node to be deleted is  
//the first node
{
current = first;
first = first->next;
if (first != NULL)
first->back = NULL;
else
last = NULL;
count--;
delete current;
}
else 
{
found = false;
current = first;
while (current != NULL && !found)  //search the list
if (current->info >= deleteItem)
found = true;
else
current = current->next;
if (current == NULL)
cout << "The item to be deleted is not in " 
<< "the list." << endl;
else if (current->info == deleteItem) //check for 
//equality
{
trailCurrent = current->back; 
trailCurrent->next = current->next;
if (current->next != NULL)
current->next->back = trailCurrent;
if (current == last)
last = trailCurrent;
count--;
delete current;
}
else
cout << "The item to be deleted is not in list." 
<< endl;
}//end else
}//end deleteNode
template <class Type>
void doublyLinkedList<Type>::copyList(const doublyLinkedList<Type>& otherList)
{
//cout << "The definition of this function is left as an exercise." << endl;
//cout << "See Programming Execrise 9." << endl;

template <class Type>
doublyLinkedList<Type>::doublyLinkedList(const doublyLinkedList<Type>& otherList)
{
// cout << "The definition of the copy constructor is left as an exercise." <<         endl;
// cout << "See Programming Execrise 9." << endl;
}
template <class Type>
const doublyLinkedList<Type>& doublyLinkedList<Type>::operator=
(const doublyLinkedList<Type> &)
//  cout << "Overloading the assignment operator is left as an exercise." << endl;
//  cout << "See Programming Execrise 9." << endl;
}
template <class Type>
doublyLinkedList<Type>::~doublyLinkedList()
{
//cout << "Definition of the destructor is left as an exercise." << endl;
//cout << "See Programming Execrise 9." << endl;
}

主要功能:

//Program to test various operations on a doubly linked list

#include <iostream>
#include "doublyLinkedList.h"  
using namespace std; 
int main()
{
char choice;
int n = 0;
doublyLinkedList<int> myList;
cout<<"this is a test"<<endl;
do {
cout<<"Main Menu:"<<endl;
cout<<"Choice of operations to perform on Dobule Linked List"<<endl;
cout<<"Create list values :  C"<<endl;
cout<<"Initialize List:   Z"<<endl;
cout<<"Check List Empty:   M"<<endl;
cout<<"Destroy List:   E  "<<endl;
cout<<"Print List  : P"<<endl;
cout<<"Reverse printed list:  R"<<endl;
cout<<"Length of List: L"<<endl;
cout <<"Front of List: F"<<endl;
cout<<"Back of List: B"<<endl;
cout<<"Search list: S"<<endl;
cout<<"Insert List: I"<<endl;
cout<<"delete list: D"<<endl;
cout<<"use copy constructor : U" <<endl;
cout <<"quit: Q"<<endl;
cin >> choice;
if ((choice == 'I' )|| (choice =='D')|| (choice == 'S'))
{
cout<<"Enter value to manipulate: "<<endl;
cin >> n;
}
switch ( choice) 
{
case 'C':
cout<<"Please enter a list"<<endl;
while(n!= -999){
myList.insert(n);
cin>>n;}
break;
case 'S':  if (myList.search(n))
cout<< " List contains: "<<n<<endl;
else
cout<<"List does not contain "<<n<<endl;
break;
case 'I': 
myList.insert(n);
cout<<"element was inserted"<<endl;
break;
case 'D':
myList.deleteNode(n);
cout<<"node was deleted"<<endl;
break;
case 'L':  cout<<"Length is n"<<endl;
myList.length();
break;
case 'B': 
cout<<"back element is :  "<< myList.back();
break;
case 'F' : 
cout<<"front element is "<<myList.front();
break;
case 'Z' : myList.initializeList();
cout<<"list initialized"<<endl;
case 'M': if (myList.isEmptyList())
cout<<"is empty"<< endl;
else
cout<<"is not empty"<<endl;
break;
case 'E': myList.destroy();
cout<<"list destroyed"<<endl;
break;
case 'P': myList.print();
break;
case'R': cout<<"reversed"<<endl;
myList.reversePrint();
break;
}
}while(choice!= 'Q');
return 0;
}

我正在寻求指导。我知道答案很简单,但我没有看到。我想过使用关键字extern,但不确定如何使用它。就像我在标签中说的,这是家庭作业,所以我不想快速解决问题,我想从错误中吸取教训。我真的很感谢这个网站和所有的会员。

我在这里发布的所有代码都是由图书出版商免费提供的,除了main.cpp 之外,我遗漏了我的原始代码

您需要将实现移动到头文件中。与普通函数不同,编译器需要能够在使用时查看所有模板代码。

有关更多信息,请参阅此问题的答案:

为什么模板只能在头文件中实现?

问题是您的主编译单元中没有可用的模板定义(它们是使用的)。

这意味着您需要为它所使用的类型进行显式实例化。

  1. 添加

    template class doublyLinkedList<int>;
    

    到doublyLinkedList.cpp的末尾,以明确地实例化它。

  2. 或者在标题中包括cpp,

  3. 或直接进入main.cpp