C++的类模板的问题(实现文件和头文件放在一起), 因为模板不支持分离编译

C++中的类模板不支持传统的分离编译方式。通常,为了防止链接错误,模板的实现必须与声明一同放在头文件中。如果尝试将模板的实现放在单独的cpp文件里,会导致'undefined reference to...'的错误。例如,当尝试将LinkedListNode、LinkedListIterator、LinkedListType和unorderedLinkedList的实现与头文件分离时,编译会出现问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先C++的模板不支持分离编译模型。如果不是模板, 那么实现文件和接口文件分开会是一个good practice in C++。 但是对于模板,  我们必须要将实现文件 和  头文件放在一起。 否则会发生undefined refernce to .....

例如下例中, 我们修改为如下, 一旦将实现文件和头文件分开, 会错的很难看的。



具体的, 各个文件如下:

LinkedListNode.h 文件如下:

#ifndef LINKED_LIST_NODE_H
#define LINKED_LIST_NODE_H
//definition of the node
template <class Type>
struct nodeType {
   Type info;
   nodeType<Type>* link;
};
#endif


LinkedListIterator.h:

#ifndef LINKED_ITERATOR
#define LINKED_ITERATOR
//This class specifies the members to implement an iterator
#include "LinkedListNode.h"
template <class Type>
class linkedListIterator {
   public:
      linkedListIterator();
      //default constructor
      //postcondition: current = NULL;

      linkedListIterator(nodeType<Type>* ptr);
      //constructors with a parameter
      //postcondition: current = ptr;

      Type operator*();
      //function to overload the dereferencing operator *
      //postcondition: returns the info contained in the node.

      linkedListIterator<Type> operator++();
      //overload the preincrement operator
      //postcondition: the iterator is advanced to the next node.

      bool operator==(const linkedListIterator<Type>& right) const;
      //overload the equality operator
      //postcondition: returns true if the iterator is equal to the
      //iterator specifies by right, otherwise it returns false.

      bool operator!=(const linkedListIterator<Type>& right) const;
      // overload the not equal to operator.
      //postcondition: returns true if this iterator is not equal
      //to the iterator specifies by right, otherwise it returns false.
   private:
      nodeType<Type>* current; //pointer to point to the current node in the linked list
};

template <class Type>
linkedListIterator<Type>::linkedListIterator() {
   current = NULL;
}

template <class Type>
linkedListIterator<Type>::linkedListIterator(nodeType<Type>* ptr) {
   current = ptr;
}

template <class Type>
Type linkedListIterator<Type>::operator*() {
   return current -> info;
}

template <class Type>
linkedListIterator<Type> linkedListIterator<Type>::operator++() {
   current = current -> link;
   return *this;
}

template <class Type>
bool linkedListIterator<Type>::operator==(const linkedListIterator<Type>& right) const {
    return (right == right.current);
}

template <class Type>
bool linkedListIterator<Type>::operator!=(const linkedListIterator<Type> &right) const {
   return (current != right.current);
}


#endif


LinkedListType.h:

#ifndef LINKED_TYPE_H
#define LINKED_TYPE_H
//this class specifies members to implement the basic properties
//of a linked list. This is an abstract class. We cannot instantiate
//an object of this class

#include "linkedListIterator.h"
#include "LinkedListNode.h"
#include <iostream>
#include "assert.h"
using namespace std;

template <class Type>
class linkedListType {
    public:
       const linkedListType<Type>& operator=(const linkedListType<Type>&);
       //overload the assignment operator

       void initializeList();
       //Initialize a list to an empty list.
       //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 it returns false.

       void print() const;
       //function to output the data contained in each node.
       //postcondition: none

       int length() const;
       //function to return the number of nodes in the list
       //postcondition: the value of count is returned.

       void destroyList();
       //function to delete all the nodes from the list
       //postcondition: first = NULL, last = NULL, count = 0;

       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 programs terminates, otherwise, the
       //first element 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 programs terminates, otherwise,
       // the last element of the list is returned.

       virtual bool search(const Type& searchItem) const = 0;
       // function to determine whether searchItem is in the list.
       //Postcondition: returns true if searchItem is in the list,
       //otherwise, the value of false is returned.

       virtual void insertFirst(const Type& newItem) = 0;
       //function to insert newItem at the beginningof the list.
       //postcondion: first points to the new list, newItem is inserted
       // at the end of the list, last points to the last node of list, and
       //count is incremented by 1;

       virtual void insertLast(const Type& newItem) = 0;
       //function to insert a newItem at the end of the list. last points to the last node in the list,
       // and count is incremented by 1.

       virtual void deleteNode(const Type& deleteItem) = 0;
       //function to delete deleteItem from the list.
       //postconditon: if found, the node containing deleteItem is deleted
       //from the list. first points to the first node, last point to the last node in
       //the updated list, and count is decremented by 1.

       linkedListIterator<Type> begin();
       // function to return an iterator at the beginning of the
       // the linked list.
       // postcondition: returns an iterator such that current is set
       // to first


       linkedListIterator<Type> end();
       // function to return an iterator one element past
       // the last element of the linked list.
       //postcondition: return an iterator such that current is set to null.

       linkedListType();
       //default constructor
       // initialize the list to an empty state.
       //postcondition: first = NULL, last = NULL, count = 0

       linkedListType(const linkedListType<Type>& otherList);
       // copy constructor.

       ~linkedListType();
       // destructor
       //delete all the nodes from the list
       //postcondition: the list object is destroyed.

   protected:
      int count; // variable to store the number of list elements
      nodeType<Type>* first;
      nodeType<Type>* last;

   private:
      void copyList(const linkedListType<Type>& otherList);
      //function to make a copy of other list.
      //postcondition: a copy of otherList is created and assigned to the list.

};

template <class Type>
const linkedListType<Type>& linkedListType<Type>::operator=
(const linkedListType<Type>& otherList) {
   if(this != &otherList) {//&: the address of, avoid self copy
      copyList(otherList);
   } // end else

   return *this;
}

template <class Type>
void linkedListType<Type>::initializeList() {
   destroyList(); //if the list has any nodes, delete them.
}

template <class Type>
bool linkedListType<Type>::isEmptyList() const {
   return (first == NULL);
}

template <class Type>
void linkedListType<Type>::print() const {
    nodeType<Type>* current;
    current = first;

    while(current != NULL) {
       cout << current -> info << " ";
       current = current -> link;
    }
}

template <class Type>
int linkedListType<Type>::length() const {
   return count;
}

template <class Type>
void linkedListType<Type>::destroyList() {
   nodeType<Type>* temp; //pointer to deallocate the memory occupied by the node

   while(first != NULL) {
      temp = first; // set temp to current node
      first = first -> link; //advance first to the next node
      delete temp; // deallocate the memory occupied by temp

   }

   last = NULL; //initialize last to NULL; first has already been
                // set to NULL by the while loop
   count = 0;
}

template <class Type>
Type linkedListType<Type>::front() const {
   assert(first != NULL);// assert terminates the program if the list is empty
                         // first != NULL is true, continue the next statements

   return first -> info; // return the info of the first node.
}

template <class Type>
Type linkedListType<Type>::back() const {
   assert(last != NULL);

   return last -> info;
}

template <class Type>
linkedListIterator<Type> linkedListType<Type>::begin() {
   linkedListIterator<Type> temp(first);

   return temp;
}

template <class Type>
linkedListIterator<Type> linkedListType<Type>::end() {
   linkedListIterator<Type> temp(NULL);

   return temp;
}

template <class Type>
linkedListType<Type>::linkedListType() {
   first = NULL;
   last = NULL;
   count = 0;
}

template <class Type>
linkedListType<Type>::linkedListType(const linkedListType<Type>& otherList) {
   first = NULL;
   copyList(otherList);
}





template <class Type>
linkedListType<Type>::~linkedListType() {
   destroyList();
}

template <class Type>
void linkedListType<Type>::copyList(const linkedListType<Type>& otherList) {
   nodeType<Type>* newNode; //pointer to create a node
   nodeType<Type>* current;

   if(first != NULL) //if the list is nor empty, make it empty
      destroyList();

   if(otherList.first == NULL) { // otherList is empty
      first = NULL;
      last = NULL;
      count = 0;
   }
   else {
      current = otherList.first;
      count = otherList.count;

      first = new nodeType<Type>;
      first -> info = current -> info;
      first -> link = NULL;
      last = first;
      current = current -> link;

      while(current != NULL) {
         newNode = new nodeType<Type>;
         newNode -> info = current -> info;
         newNode -> link = NULL;
         last -> link = newNode;
         last = newNode;
         current = current -> link;
      }
   }
}





#endif



unorderedLinkedListr.h:

#ifndef UNORDER_H
#define UNORDER_H

#include "LinkedListType.h"
using namespace std;

template <class Type>
class unorderedLinkedList: public linkedListType<Type> {
   public:
      bool search(const Type&) const;
      void insertFirst(const Type&);
      void insertLast(const Type&);
      void deleteNode(const Type&);
};


template <class Type>
bool unorderedLinkedList<Type>::search(const Type& searchItem) const {
   nodeType<Type>* current;
   bool found = false;
   current = this -> first;
   while(current != NULL && !found)
      if(current -> info == searchItem) {
         found = true;
      }
      else
         current = current -> link;
   return found;

}

template <class Type>
void unorderedLinkedList<Type>::insertFirst(const Type& item) {
   nodeType<Type>* newNode;
   newNode = new nodeType<Type>;
   newNode -> info = item;
   newNode -> link = this ->first;
   this -> first = newNode;
   this -> count++;
   if(this -> last == NULL)
      this -> last = newNode;
}

template <class Type>
void unorderedLinkedList<Type>::insertLast(const Type& item) {
   nodeType<Type>* newNode;
   newNode = new nodeType<Type>;

   newNode -> info = item;
   newNode -> link = NULL;

   if(this -> first == NULL) {
      this -> first = newNode;
      this -> last = newNode;
      this -> count++;
   }
   else {
      this -> last -> link = newNode;
      this -> last = newNode;
      this -> count ++;
   }
//   last -> link = newNode;
//   last = newNode;
//   count++;
//
//   if(first == NULL)
//      first = newNode;
}


template <class Type>
void unorderedLinkedList<Type>::deleteNode(const Type& item) {
   nodeType<Type>* current;
   nodeType<Type>* trailCurrent;
   bool found;
   if(this -> first == NULL){
      cout << "The list is empty." << endl;
   }
   else {
      if(this -> first -> info == item) {
         current = this -> first;
         this -> first = this -> first -> link;
         this -> count--;
         if(this -> first == NULL)
            this -> last = NULL;
         delete current;
      }
      else {
         found = false;
         trailCurrent =this -> first;
         current = this -> first -> link;
         while(current != NULL && !found) {
            if(current -> info != item) {
               trailCurrent = current;
               current = current -> link;
            }
            else
               found = true;
         }
         if(found) {
            trailCurrent -> link = current -> link;
            this -> count--;
            if(this -> last == current)
               this -> last = trailCurrent;
            delete current;

         }
         else
           cout << "Item is not found in the list." << endl;
      }
   }
}



#endif


main.cpp:

//This program tests various operation of a linked list
//34 62 21 90 66 53 88 24 10 -999

#include <iostream>
#include "unorderedLinkedList.h"

using namespace std;

int main() {
    unorderedLinkedList<int> list1, list2;          //Line 1
    int num;                                        //Line 2

    cout << "Line 3: Enter integers ending "
         << "with -999" << endl;                    //Line 3
    cin >> num;                                     //Line 4

    while (num != -999)                             //Line 5
    {
        list1.insertLast(num);                      //Line 6
        cin >> num;                                 //Line 7
    }

    cout << endl;                                   //Line 8

    cout << "Line 9: list1: ";                      //Line 9
    list1.print();                                  //Line 10
    cout << endl;                                   //Line 11
    cout << "Line 12: Length of list1: "
         << list1.length() << endl;                 //Line 12

    list2 = list1;	   //test the assignment operator Line 13

    cout << "Line 16: list2: ";                     //Line 14
    list2.print();                                  //Line 15
    cout << endl;                                   //Line 16
    cout << "Line 17: Length of list2: "
         << list2.length() << endl;                 //Line 17

    cout << "Line 18: Enter the number to be "
         << "deleted: ";                            //Line 18
    cin >> num;                                     //Line 19
    cout << endl;                                   //Line 20

    list2.deleteNode(num);                          //Line 21

    cout << "Line 22: After deleting " << num
         << " list2: " << endl;                     //Line 22
    list2.print();                                  //Line 23
    cout << endl;                                   //Line 24

    cout << "Line 25: Length of list2: "
         << list2.length() << endl;                 //Line 25

    cout << endl << "Line 26: Output list1 "
         << "using an iterator" << endl;            //LIne 26

    linkedListIterator<int> it;                     //Line 27

    for (it = list1.begin(); it != list1.end();
                             ++it)                  //Line 28
        cout << *it << " ";                         //Line 29
    cout << endl;                                   //Line 30

    return 0;
}

运行结果如下:




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值