Possible Duplicate:
Why can templates only be implemented in the header file?
What is an undefined reference/unresolved external symbol error and how do I fix it?
Again this is a homework assignment and my instructor has given us plenty of feedback but I am still at a lost for this compile issue.
When I place the main function inside the implementation file the program compiles and works perfectly. However when I place the main function into main.cpp the compiler complains:
unresolved external symbol "public: __thiscall doublyLinkedList<int>::doublyLinkedList<int>(void)" (??0?$doublyLinkedList@H@@QAE@XZ) referenced in function
Header File
#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
Implementation file:
#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;
}
Main Function:
//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;
}
I am looking for guidance. I know the answer is really simple and I am just not seeing it. I thought about using the keyword extern but am not sure really how to use it. Like I said in the tags this is homework so I am not looking for a quick fix I am looking to learn from my mistakes.
I really appreciate this site and all the members.
All the code i posted on here was available for free by the book publisher, I have left out my original code except for main.cpp
You need to move your implementation into the header file. Unlike normal functions the compiler needs to be able to see all of the template code at the point of use.
See the answers in this question for more information:
Why can templates only be implemented in the header file?