5

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

Community
  • 1
  • 1
Craig
  • 173
  • 4
  • 15

2 Answers2

5

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?

Community
  • 1
  • 1
3

The problem is that you don't have the template definitions available in your main compilation unit (where they are used).

This means you need to have explicit instantiations for the types it is used with.

  1. Add

    template class doublyLinkedList<int>;
    

    to the end of doublyLinkedList.cpp to explicitely instantiate it.

  2. Or include the cpp in the header,

  3. or directly into main.cpp

sehe
  • 374,641
  • 47
  • 450
  • 633