可能重复:
为什么模板只能在头文件中实现?
我正在尝试使用一个在链表上创建和执行操作的程序。
该程序按原样工作和编译,但我必须创建一个可以处理任何类型数据(int、float、char)的程序模板版本。程序中有两个类,NodeSLList 类和 IntNode 类。
我已尽力创建这两个类的模板版本,同时按我认为应该的方式更改成员声明和定义,但对于我的生活,我无法摆脱其中一些错误。我正在阅读和重新阅读关于模板和模板类的笔记,并在网上搜索以获得更好的解释,并且在发布此内容时将继续工作,但同时我非常感谢任何帮助。
有两个源代码文件和两个头文件。
IntNode.h:
///////////////////////////////////////////////////////////////////////
// class IntNode
//
// Description: represents the data that we want to store in our
// linked list
///////////////////////////////////////////////////////////////////////
#ifndef __INT_NODE__
#define __INT_NODE__
#include <iostream>
using std::ostream;
// class declaration
template <typename N>
class IntNode {
// make the following friends of this class in order that they be
// able to directly access private data of this container class
friend void NodeSLList_Test(void);
friend class NodeSLList;
friend class TSArray;
friend ostream& operator<<(ostream &, NodeSLList &);
public:
///////////////////////////////////////////////////////////////////////
// ostream operator
//
// Description: provide overloaded ostream operator
// Input: reference to ostream object
// reference to IntNode object to output
// Output: none
// Returns: reference to same ostream operator for cascading
///////////////////////////////////////////////////////////////////////
friend ostream& operator<<(ostream & out, IntNode<N> & n);
///////////////////////////////////////////////////////////////////////
// default constructor
//
// Description: provide default construction of an IntNode object
// Input: row of array
// column of array
// depth of array
// initial value of node
// pointer to next IntNode
// Output: none
// Returns: reference to same ostream operator for cascading
///////////////////////////////////////////////////////////////////////
IntNode(int inRow=0, int inCol=0, int inDepth=0, N inData, IntNode<N> *in = 0);
///////////////////////////////////////////////////////////////////////
// GetRow
//
// Description: return row member
// Input: none
// Output: none
// Returns: row member
///////////////////////////////////////////////////////////////////////
const int GetRow() const;
///////////////////////////////////////////////////////////////////////
// GetColumn
//
// Description: return column member
// Input: none
// Output: none
// Returns: column member
///////////////////////////////////////////////////////////////////////
const int GetColumn() const;
///////////////////////////////////////////////////////////////////////
// GetDepth
//
// Description: return depth member
// Input: none
// Output: none
// Returns: depth member
///////////////////////////////////////////////////////////////////////
const int GetDepth() const;
///////////////////////////////////////////////////////////////////////
// GetData
//
// Description: return data member
// Input: none
// Output: none
// Returns: data member
///////////////////////////////////////////////////////////////////////
const N GetData() const;
private:
///////////////////////////////////////////////////////////////////////
// row
//
// this variable holds the row of the array element (i.e first demension)
///////////////////////////////////////////////////////////////////////
int row;
///////////////////////////////////////////////////////////////////////
// column
//
// this variable holds the column of the array element (i.e 2nd demension)
///////////////////////////////////////////////////////////////////////
int col;
///////////////////////////////////////////////////////////////////////
// depth
//
// this variable holds the column of the array element (i.e 3rd demension)
///////////////////////////////////////////////////////////////////////
int depth;
///////////////////////////////////////////////////////////////////////
// data
//
// this variable holds the actual data at the array element
///////////////////////////////////////////////////////////////////////
N data;
///////////////////////////////////////////////////////////////////////
// column
//
// this variable holds the column of the array element (i.e 2nd demension)
///////////////////////////////////////////////////////////////////////
IntNode<N> *next;
};
#endif __INT_NODE__
IntNode.cpp:
///////////////////////////////////////////////////////////////////////
// class IntNode
//
// Description: represents the data that we want to store in our
// linked list
///////////////////////////////////////////////////////////////////////
#include "IntNode.h"
///////////////////////////////////////////////////////////////////////
// default constructor
template <typename N>
IntNode<N>::IntNode(int inRow, int inCol, int inDepth, N inData, IntNode *in)
{
data = inData;
next = in;
row = inRow;
col = inCol;
depth = inDepth;
}
///////////////////////////////////////////////////////////////////////
// GetRow
///////////////////////////////////////////////////////////////////////
template <typename N>
const int IntNode<N>::GetRow() const
{
return row;
}
///////////////////////////////////////////////////////////////////////
// GetColumn
///////////////////////////////////////////////////////////////////////
template <typename N>
const int IntNode<N>::GetColumn() const
{
return col;
}
///////////////////////////////////////////////////////////////////////
// GetDepth
///////////////////////////////////////////////////////////////////////
template <typename N>
const int IntNode<N>::GetDepth() const
{
return depth;
}
///////////////////////////////////////////////////////////////////////
// GetData
///////////////////////////////////////////////////////////////////////
template <typename N>
const N IntNode<N>::GetData() const
{
return data;
}
///////////////////////////////////////////////////////////////////////
// ostream operator
///////////////////////////////////////////////////////////////////////
template <typename N>
ostream& operator<<(ostream & out, IntNode<N> & n)
{
out << "[" << n.row << "]"
<< "[" << n.col << "]"
<< "[" << n.depth << "]:"
<< n.data;
return out;
}
节点SLList.h:
///////////////////////////////////////////////////////////////////////
// Class NodeSLList Interface
//
// Description - This is the interface for a class which implements
// a singly linked list of integers. Each node in the
// linked list is IntNode object, defined by the IntNode
// class.
///////////////////////////////////////////////////////////////////////
#ifndef INT_LINKED_LIST
#define INT_LINKED_LIST
#include <iostream>
using std::ostream;
using std::cout;
using std::cin;
using std::endl;
#include "IntNode.h"
// Class NodeSLList Declaration
template <typename T>
class NodeSLList {
///////////////////////////////////////////////////////////////////////
// operator<<
//
// Description: print the list
// Input: reference to ostream object
// reference to an NodeSLList object to be printed
// Output: linked list printed to screen
// Returns: reference to an ostream object
///////////////////////////////////////////////////////////////////////
//friend ostream& operator<<( ostream &, NodeSLList<T> & );
template <typename T> friend ostream & operator<<(ostream &, NodeSLList<T> &);
public:
///////////////////////////////////////////////////////////////////////
// default constructor
//
// Description: initialize list
// Input: none
// Output: none
// Returns: none
///////////////////////////////////////////////////////////////////////
NodeSLList();
///////////////////////////////////////////////////////////////////////
// destructor
//
// Description: deallocates all memory for linked list by calling
// destroyList() member function
// Input: none
// Output: none
// Returns: none
///////////////////////////////////////////////////////////////////////
~NodeSLList();
///////////////////////////////////////////////////////////////////////
// IsEmpty
//
// Description: returns status of array
// Input: none
// Output: none
// Returns: TRUE if list is empty
// FALSE otherwise
///////////////////////////////////////////////////////////////////////
bool IsEmpty() const;
///////////////////////////////////////////////////////////////////////
// GetSize
//
// Description: get current number of nodes in list
// Input: none
// Output: none
// Returns: number of nodes in list
///////////////////////////////////////////////////////////////////////
int GetSize() const;
///////////////////////////////////////////////////////////////////////
// AddToHead
//
// Description: add a node to the head of the list
// Input: data for node to be added
// Output: updated linked list
// Returns: none
///////////////////////////////////////////////////////////////////////
void AddToHead(IntNode<T> & node);
///////////////////////////////////////////////////////////////////////
// DeleteFromHead
//
// Description: remove a node from the head of the list
// Input: none
// Output: updated linked list
// Returns: data that was at the node just removed
///////////////////////////////////////////////////////////////////////
IntNode<T> DeleteFromHead();
///////////////////////////////////////////////////////////////////////
// DeleteFromTail
//
// Description: remove a node from the tail of the list
// Input: none
// Output: updated linked list
// Returns: data that was at the node just removed
///////////////////////////////////////////////////////////////////////
IntNode<T> DeleteFromTail();
///////////////////////////////////////////////////////////////////////
// DeleteNode
//
// Description: remove a node from the list
// Input: node number to be removed
// Output: updated linked list
// Returns: data that was at the node just removed
///////////////////////////////////////////////////////////////////////
IntNode<T> DeleteNode(int nodeNum);
///////////////////////////////////////////////////////////////////////
// RetrieveNode
//
// Description: retrieve data from a node without removing it from
// the list
// Input: node number (1-N; not 0-N-1)
// Output: none
// Returns: reference to node data
///////////////////////////////////////////////////////////////////////
IntNode<T> &RetrieveNode(int nodeNum) const;
///////////////////////////////////////////////////////////////////////
// UpdateNode
//
// Description: update a node's data
// Input: node number (1-N; not 0-(N-1))
// Output: updated node
// Returns: none
///////////////////////////////////////////////////////////////////////
void UpdateNode(int nodeNum, IntNode<T> &node);
///////////////////////////////////////////////////////////////////////
// DestroyList
//
// Description: deallocates all memory for linked list
// Input: none
// Output: reset linked list
// Returns: none
///////////////////////////////////////////////////////////////////////
void DestroyList();
private:
IntNode<T> *head, *tail;
};
#endif INT_LINKED_LIST
节点SLList.cpp:
///////////////////////////////////////////////////////////////////////
// Class NodeSLList Implementation
//
// Description - This file implements a singly linked list.
///////////////////////////////////////////////////////////////////////
#include "IntNode.h"
#include "NodeSLList.h"
///////////////////////////////////////////////////////////////////////
// default constructor
///////////////////////////////////////////////////////////////////////
template <typename T>
NodeSLList<T>::NodeSLList()
{
head = tail = 0;
}
///////////////////////////////////////////////////////////////////////
// destructor
////////////////////////////////////////////////////////////////////
template <typename T>
NodeSLList<T>::~NodeSLList()
{
// call destroyList() to remove all nodes
// and reset linked list
DestroyList();
}
///////////////////////////////////////////////////////////////////////
// IsEmpty
////////////////////////////////////////////////////////////////////
template <typename T>
bool NodeSLList<T>::IsEmpty() const
{
return (head == 0);
}
///////////////////////////////////////////////////////////////////////
// DestroyList
///////////////////////////////////////////////////////////////////////
template <typename T>
void NodeSLList<T>::DestroyList()
{
// while the list is NOT empy
// keep removing the head node and make
// the next node the head node
for (IntNode<T> *p; !IsEmpty(); )
{
p = head->next;
delete head;
head = p;
}
head = tail = 0;
}
///////////////////////////////////////////////////////////////////////
// AddToHead
///////////////////////////////////////////////////////////////////////
template <typename T>
void NodeSLList<T>::AddToHead(IntNode<T> & node)
{
// create a new node, and make it the head. the
// previous head will become head->next
head = new IntNode<>(node.row, node.col, node.depth, node.data, head);
// if this is the first node, make the tail the
// same as the head
if (tail == 0)
tail = head;
}
///////////////////////////////////////////////////////////////////////
// DeleteFromHead
//
// Description: remove a node from the head of the list
// Input: none
// Output: updated linked list
// Returns: data that was at the node just removed
///////////////////////////////////////////////////////////////////////
template <typename T>
IntNode<T> NodeSLList<T>::DeleteFromHead()
{
IntNode<T> temp;
if (IsEmpty())
{
cout << "*****ERROR: Can't delete from head. List is Empty" << endl;
return temp;
}
temp.data = head->data;
temp.col = head->col;
temp.row = head->row;
temp.depth = head->depth;
IntNode<T> *tmp = head;
// if there is only one node, set the head and pointer tails
// to NULL (0)
if (head == tail)
head = tail = 0;
// otherwise, move the head pointer to the next node
// in the list
else
head = head->next;
// delete head node
delete tmp;
return temp;
}
///////////////////////////////////////////////////////////////////////
// DeleteFromTail
///////////////////////////////////////////////////////////////////////
template <typename T>
IntNode<T> NodeSLList<T>::DeleteFromTail()
{
IntNode<T> nodeData;
nodeData.col = tail->col;
nodeData.row = tail->row;
nodeData.depth = tail->depth;
nodeData.data = tail->data;
// if there is only one node, delete the only node, and set the
// head and tail pointers to NULL (0)
if (head == tail)
{
delete head;
head = tail =0;
}
// otherwise, traverse to the tail node and delete it
else
{
IntNode * temp;
for (temp = head; temp->next != tail; temp = temp->next);
delete tail;
tail = temp;
tail->next = 0;
}
return nodeData;
}
///////////////////////////////////////////////////////////////////////
// DeleteNode
///////////////////////////////////////////////////////////////////////
template <typename T>
IntNode<T> NodeSLList<T>::DeleteNode(int nodeNum)
{
if (nodeNum <= 0) nodeNum = 1;
IntNode<T> *prev=head , *temp=head;
IntNode<T> current;
// traverse to the node
for (int loop=1; loop<nodeNum; loop++)
{
prev=temp, temp=temp->next;
// check for case where nodeNum is > the number of
// nodes in the list. if we reach the tail before
// we traverse to the node, delete the tail
if ( temp == tail )
return DeleteFromTail();
}
// if deleting the head just call
// the appropriate member function
// and don't repeat that logic here
if (temp == head) return DeleteFromHead();
// otherwise, delete the node we traversed to
prev->next = temp->next;
current.row = temp->row;
current.col = temp->col;
current.data = temp->data;
delete temp;
return current;
}
///////////////////////////////////////////////////////////////////////
// RetrieveNode
///////////////////////////////////////////////////////////////////////
template <typename T>
IntNode<T> & NodeSLList<T>::RetrieveNode(int nodeNum) const
{
IntNode<T> *tmp = head;
// traverse to the node, or to the last node, whichever comes
// first
for (int i=1; i< nodeNum && tmp != tail; i++)
tmp = tmp->next;
return *tmp;
}
///////////////////////////////////////////////////////////////////////
// UpdateNode
///////////////////////////////////////////////////////////////////////
template <typename T>
void NodeSLList<T>::UpdateNode(int nodeNum, IntNode<T> &node)
{
IntNode<T> *tmp = head;
// traverse to the node, or to the last node, whichever comes
// first
for (int i=1; i< nodeNum && tmp != tail; i++)
tmp = tmp->next;
tmp->data = node.data;
tmp->col = node.col;
tmp->row = node.row;
}
///////////////////////////////////////////////////////////////////////
// GetSize
///////////////////////////////////////////////////////////////////////
template <typename T>
int NodeSLList<T>::GetSize() const
{
// check to see if the list is empty. if
// so, just return 0
if ( IsEmpty() ) return 0;
int size = 1;
IntNode<T> *p = head;
// compute the number of nodes and return
while (p != tail)
{
size++;
p = p->next;
}
return size;
}
///////////////////////////////////////////////////////////////////////
// operator<<
///////////////////////////////////////////////////////////////////////
template <typename T>
ostream & operator<<(ostream & output, NodeSLList<T> & sl)
{
IntNode<T> *p = sl.head;
if ( sl.IsEmpty())
{
output << "List is empty!";
return output;
}
output << "[row][col][depth]:data = ";
output << *p << ", ";
while (p != sl.tail)
{
p = p->next;
output << *p << ", ";
}
return output;
}
// TEST DRIVER. Only used to test the class.
// Activated by defining TEST_DRIVER in the
// Project - Settings - C/C++ - Preprocessor definitions
#ifdef LIST_DRIVER
#include <stdlib.h>
void pause();
void main(void)
{
NodeSLList_Test<int>();
NodeSLList_Test<double>();
NodeSLList_Test<float>();
}
template <typename T>
void NodeSLList_Test()
{
NodeSLList<T> s;
IntNode<T> temp;
cout << "TESTING "<<T<<" OPERATIONS\n";
IntNode<T> n1(1,1,1,10);
IntNode<T> n2(1,2,1,20);
IntNode<T> n3(1,3,1,30);
IntNode<T> n4(1,4,1,40);
IntNode<T> n5(1,5,1,50);
cout << "Testing addToHead() operation" << endl;
s.AddToHead(n5);
s.AddToHead(n4);
s.AddToHead(n3);
s.AddToHead(n2);
s.AddToHead(n1);
cout << s << endl;
cout << "\nTesting GetSize() operation" << endl;
cout << "list contains " << s.GetSize() << " node(s)" << endl;
cout << "\nTesting DeleteFromHead() operation" << endl;
temp = s.DeleteFromHead();
cout << "node retrieved " << temp << endl;
cout << s << endl;
cout << "\nTesting DeleteFromTail() operation" << endl;
temp = s.DeleteFromTail();
cout << "node retrieved " << temp << endl;
cout << s << endl;
cout << "\nTesting RetrieveNode() operation" << endl;
temp = s.RetrieveNode(0);
cout << "node retrieved (should be first node) " << temp << endl;
temp = s.RetrieveNode(50);
cout << "node retrieved (should be last node) " << temp << endl;
temp = s.RetrieveNode(2);
cout << "node retrieved (should be 2nd node) " << temp << endl;
pause();
cout << "Adding n3 to head" << endl;
cout << "Adding n2 to head" << endl;
s.AddToHead(n3);
s.AddToHead(n2);
cout << "List is now: " << s << endl;
cout << "\nTesting DeleteNode() operation" << endl;
temp = s.DeleteNode(50);
cout << "node deleted (should be last node) " << temp << endl;
cout << s << endl;
temp = s.DeleteNode(3);
cout << "node deleted (should be 3rd node) " << temp << endl;
cout << s << endl;
cout << "Test SsEmpty() operation" << endl;
cout << (s.IsEmpty() ? "List IS Empty\n" : "List NOT Empty\n");
cout << "\nTesting UpdateNode() operation (updating 3rd node with [10][20][30]:500)"
<< endl;
temp.row = 10;
temp.col = 20;
temp.depth = 30;
temp.data = 500;
s.UpdateNode(3,temp);
cout << s << endl;
pause();
cout << "\nTesting the ability to delete nodes from head, even" << endl
<< "after list is empty" << endl
<< "Should recieve 2 errors" << endl;
temp = s.DeleteFromHead();
temp = s.DeleteFromHead();
temp = s.DeleteFromHead();
temp = s.DeleteFromHead();
temp = s.DeleteFromHead();
cout << "\nTest IsEmpty() operation" << endl;
cout << (s.IsEmpty() ? "List IS Empty\n" : "List NOT Empty\n");
cout << "\nTesting DestroyList() operation" << endl;
s.AddToHead(n3);
s.AddToHead(n2);
s.AddToHead(n1);
cout << s << endl;
cout << "calling DestoryList()" << endl;
s.DestroyList();
cout << s << endl;
}
void pause()
{
cout << "Press RETURN to continue" << endl;
cin.get();
system("cls");
}
#endif
错误:
Error 1 error C2989: 'NodeSLList' : class template has already been declared as a non-class template c:\cis554\nodesllist_template\nodesllist.h 160
Error 2 error C3857: 'NodeSLList': multiple template parameter lists are not allowed c:\cis554\nodesllist_template\nodesllist.h 23
Error 3 error C2988: unrecognizable template declaration/definition c:\cis554\nodesllist_template\nodesllist.cpp 14
Error 4 error C2059: syntax error : '<' c:\cis554\nodesllist_template\nodesllist.cpp 14
Error 5 error C2588: '::~NodeSLList' : illegal global destructor c:\cis554\nodesllist_template\nodesllist.cpp 24
Error 6 error C1903: unable to recover from previous error(s); stopping compilation c:\cis554\nodesllist_template\nodesllist.cpp 24
7 IntelliSense: default argument not at end of parameter list c:\CIS554\NodeSLList_Template\IntNode.h 51