一个链表的类模板,为什么放一个文件里可以,分开的话就一堆链接错误?

bugzhao 2006-03-10 05:36:23
这个程序是C++primer里面的,我一个字一个字敲进去,出一堆链接错误,百思不得其解,
后来想了想,把那几个cpp、h文件,都放在一个主文件里了,居然成功了,
请问这是为何呢?

放在一个文件里的源代码如下(很长)



#ifndef LIST_H_
#define LIST_H_
#pragma warning(disable:4786)
#include <vector>
#include <bitset>
#include <complex>
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cassert>
#include <string>
#include <fstream>
#include <WTYPES.H>
#endif
using namespace std;

template <class elemType>
class list_item{
public:
//构造函数
list_item(elemType value,list_item<elemType> *item=NULL);

list_item<elemType> *getNext() {return _next;}
void setNext(list_item *link) {_next=link;}

elemType getValue(void) {return _value; }
void setValue(elemType new_value) {_value=new_value;}

private:
elemType _value;
list_item<elemType> *_next;
};

template <class elemType>
class list{
public:
//构造函数
list():_front(NULL),_end(NULL),_size(0){}

//拷贝构造函数
list(const list<elemType> &rhs);

//重载赋值操作符
list & operator= (const list<elemType> &rhs);

int getSize(void) {return _size;}
void setSize(int s) {_size=s;}

list_item<elemType> * getEnd(void) {return _end; }
void setEnd(list_item<elemType> *e) {_end=e;}

list_item<elemType> * getFront(void) {return _front; }
void setFront(list_item<elemType> *f) {_front=f;}

//在指针ptr处插入一个新的结点,其值为value
void insert(list_item<elemType> *ptr,elemType value);

//在头部插入一个新值
void insert_front(elemType value);

//在尾部插入一个新值
void insert_end(elemType value);

//删除头部元素(结点)
void remove_front(void);

//删除尾部元素
void remove_end(void);

//删除全部
void remove_all(void);

//删除结点值为value的结点
void remove(elemType value);

//删除指针处的结点
void remove(list_item<elemType> *ptr);

//翻转链表
void reverse(void);

//连接两个链表
void concat(const list &il);

//查找第一个值为value的结点
list_item<elemType> *find(elemType value);

//打印全部链表
void display(ostream &os=cout);

//插入全新元素
void insert_all(const list<elemType> &rhs);

private:
list_item<elemType> *_front;
list_item<elemType> *_end;
list_item<elemType> *_current;
int _size;
};



template <class elemType>
list_item<elemType>::list_item(elemType value,list_item<elemType> *item):_value(value)
{
if(!item)
_next=NULL;
else
{
_next=item->_next;
item->_next=this;
}
}

//------------------------------------------------------------------------

template <class elemType>
list_item<elemType> * list<elemType>::find (elemType value)
{
list_item<elemType> *ptr=_front;
while(ptr)
{
if(ptr->getValue() == value)
return ptr;
ptr=ptr->getNext ();
}
return NULL;
}

template <class elemType>
void list<elemType>::display (ostream &os/* =cout */)
{
os<<"\n( "<<_size<< " )( ";
list_item<elemType> *ptr=_front;
while(ptr){
os<<ptr->getValue ()<<" ";
ptr=ptr->getNext ();
}
os<<")\n";
}

template <class elemType>
void list<elemType>::insert (list_item<elemType> *ptr,elemType value)
{
if(!ptr)
insert_front(value);
else
{
new list_item<elemType>(value,ptr);
++_size;
}
}

template <class elemType>
void list<elemType>::insert_front(elemType value)
{
list_item<elemType> *ptr=new list_item<elemType>(value);
if(!_front)
_front=_end=ptr;
else{
ptr->setNext(_front);
_front=ptr;
}
++_size;
}

template <class elemType>
void list<elemType>::insert_end (elemType value)
{
if(!_end)
_end=_front=new list_item<elemType>(value);
else _end=new list_item<elemType>(value,_end);
++_size;
}

template <class elemType>
void list<elemType>::remove_front (void)
{
if(_front){
list_item<elemType> *ptr=_front;
_front=_front->getNext ();
--_size;
delete ptr;
}
}

template <class elemType>
void list<elemType>::remove_all (void)
{
while(_front)
remove_front();

_size=0;
_front=_end=NULL;
}

template <class elemType>
void list<elemType>::remove (list_item<elemType> *ptr)
{
list_item<elemType> *p;
p=_front;

if(!ptr)
return;
else if(p==ptr){
remove_front();
return;
}

while(p){
if(p->getNext() ==ptr){
p->setNext(ptr->getNext ()) ;
--_size;
delete ptr;
break;
}
p=p->getNext ();
}
}

template <class elemType>
void list<elemType>::remove (elemType value)
{
list_item<elemType> *ptr;
ptr=find(value);
remove(ptr);
}

template <class elemType>
void list<elemType>::remove_end (void)
{
list_item<elemType> *p;
p=_front;

if(!p)
return;

while(p->getNext ()!=_end)
p=p->getNext ();

delete p->getNext ();
_end=p;
p->setNext (NULL);
--_size;
}

template <class elemType>
void list<elemType>::concat (const list<elemType> &il)
{
if(!_end){
_front=il._front ;
_size=il._size;
}
else{
_end->setNext (il._front) ;
_size+=il._size ;
}
_end=il._end ;
}

template <class elemType>
void list<elemType>::reverse(void)
{
list_item<elemType> *ptr=_front;
list_item<elemType> *prev=NULL;

_front=_end;
_end=ptr;

while(ptr!=_front)
{
list_item<elemType> *tmp=ptr->getNext ();
ptr->setNext (prev);
prev=ptr;
ptr=tmp;
}

_front->setNext (prev);
}

template <class elemType>
void list<elemType>::insert_all (const list<elemType> &rhs)
{
list_item<elemType> *ptr=rhs._front ;
while (ptr) {
insert_end(ptr->getValue());
ptr=ptr->getNext();
}
}

template <class elemType>
list<elemType>::list (const list<elemType> &rhs):_front(NULL),_end(NULL),_size(0)
{
insert_all(rhs);
}

template <class elemType>
list<elemType> & list<elemType>::operator = (const list<elemType> &rhs)
{
if(this!=&rhs){
remove_all();
insert_all(rhs);
}
return *this;
}

int main()
{
list<int> mylist;

for (int ix=0;ix<5;ix++){
mylist.insert_front (ix);
if(ix!=0) mylist.insert_end (-ix);
}

cout<<"原始链表:";
mylist.display ();

cout<<"在4的后面插入400:";
mylist.insert (mylist.find (4),400);

list_item<int> *ptr;
ptr=mylist.getFront ();
mylist.insert (ptr,20);
mylist.insert_end (-50);
mylist.insert_front (100);
cout<<"在头元素后面插入20,尾部插入-50,再将100添到表头部:";
mylist.display ();

ptr=mylist.getEnd ();
list_item<int> *pnew=new list_item<int>(1981,ptr);
mylist.setEnd(pnew);
mylist.setSize (mylist.getSize ()+1);
cout<<"在尾部插入1981";
mylist.display ();

mylist.remove_front ();
cout<<"删除头部:";
mylist.display ();

ptr=mylist.getFront ();
ptr=ptr->getNext ()->getNext ();
mylist.remove (ptr);
cout<<"删除第3个元素:";
mylist.display ();

mylist.remove_end ();
cout<<"删除尾部:";
mylist.display ();

cout<<"删除0、20、9(如果没有,则不删除):";
mylist.remove (0);
mylist.remove (20);
mylist.remove (9);
mylist.display ();

mylist.insert (mylist.find (400),4000);
cout<<"在400的后面插入4000(如果找不到的话则放头部):";
mylist.display ();

list<int> mylist2;
mylist2.insert_front(300);
mylist2.insert_front (301);
mylist2.insert_end(299);
mylist.concat (mylist2);
cout<<"连接两个链表:";
mylist.display ();

mylist.reverse ();
cout<<"翻转链表:";
mylist.display ();

mylist.remove_end ();
cout<<"删除尾部:";
mylist.display ();

list<int> mylist3;
mylist3=mylist;
cout<<"链表的赋值:";
mylist3.display ();

list<int> mylist4(mylist);
cout<<"链表的拷贝构造函数:";
mylist4.display ();

mylist.remove_all ();
cout<<"删除整个链表:";
mylist.display ();

return 0;
}
...全文
107 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
bugzhao 2006-03-11
  • 打赏
  • 举报
回复
明白了,意思是模板本身不占空间啊,得实例化才行
谢谢各位了
逸学堂 2006-03-10
  • 打赏
  • 举报
回复
模板使用方法是声明与实现必须在同一个文件内..
主要原因还是编译器不支持分开.
现在STL,声明和实现都是在一个文件内的..
积木 2006-03-10
  • 打赏
  • 举报
回复
编译器现在支持了么?
似乎还没有相关的消息放出来。
蒋晟 2006-03-10
  • 打赏
  • 举报
回复
exporting templates is not supported by most compiler.
wshcdr 2006-03-10
  • 打赏
  • 举报
回复
//Test.h
template<class T>
void foo(const T &t1);

// Test.cpp
export template <class T>
void foo( T &t1)
{

}
wshcdr 2006-03-10
  • 打赏
  • 举报
回复
使用export关键字
xiao_xiao_zi 2006-03-10
  • 打赏
  • 举报
回复
对于普通的类,编译的时候只需要一个声明就可以了
连接的时候才需要定义
而对于模板类,由于编译器需要进行具现化,没有定义它就无法进行这个动作
现在的编译器还不支持模板的声明和定义在不同文件
sankt 2006-03-10
  • 打赏
  • 举报
回复
模板的声明和定义不能放在不同的文件
编译器支持不够
bugzhao 2006-03-10
  • 打赏
  • 举报
回复
上面的代码在一个cpp文件中可以运行,
但我分拆为3个文件后就不行了
第一个文件是list.cpp,其包含了这两个类的实现
第二个文件是list.h,其包含了这两个类的声明
第三个文件是test.cpp,就是main函数部分

build后出现如下错误:
Linking...
test.obj : error LNK2001: unresolved external symbol "public: void __thiscall list<int>::remove_all(void)" (?remove_all@?$list@H@@QAEXXZ)
test.obj : error LNK2001: unresolved external symbol "public: __thiscall list<int>::list<int>(class list<int> const &)" (??0?$list@H@@QAE@ABV0@@Z)
...........


奇怪的是,只有类模板才这样的,我按照这个分拆方法,把int型的链表成功实现过(也是拆为这3个文件)

64,685

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧