5

重複の可能性:
テンプレートをヘッダーファイルにのみ実装できるのはなぜですか?
未定義の参照/未解決の外部シンボルエラーとは何ですか?それを修正するにはどうすればよいですか?

繰り返しになりますが、これは宿題であり、私のインストラクターからたくさんのフィードバックが寄せられましたが、このコンパイルの問題についてはまだ迷っています。

main関数を実装ファイル内に配置すると、プログラムがコンパイルされ、完全に機能します。ただし、main関数を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を除いて、元のコードは省略しました。

4

2 に答える 2

5

実装をヘッダーファイルに移動する必要があります。通常の関数とは異なり、コンパイラは使用時にすべてのテンプレートコードを表示できる必要があります。

詳細については、この質問の回答を参照してください。

テンプレートをヘッダーファイルにのみ実装できるのはなぜですか?

于 2012-10-05T18:35:50.163 に答える
3

問題は、メインのコンパイルユニット(それらが使用されている場所)で使用可能なテンプレート定義がないことです。

これは、使用されるタイプの明示的なインスタンス化が必要であることを意味します。

  1. 追加

    template class doublyLinkedList<int>;
    

    doublyLinkedList.cppの最後に移動して、明示的にインスタンス化します。

  2. または、ヘッダーにcppを含めます。

  3. または直接main.cppに

于 2012-10-05T18:40:41.813 に答える