模板类的定义与模板类成员函数的实现分别在(.h和.cpp)的过程出现的问题

diaolingle 2013-05-17 09:16:32
//queue.h
#ifndef QUEUE_H
#define QUEUE_H
template<class Type>class Queue;
template<class Type> class QueueItem{
friend class Queue<Type>;
QueueItem(const Type &t):item(t),next(0){}
Type item;
QueueItem *next;
};
template<class Type>class Queue{
public:
Queue():head(0),tail(0){}
Queue(const Queue &Q):head(0),tail(0){copy_elems(Q);}
Queue& operator=(const Queue&);
~Queue(){destroy();}
Type &front() {return head->item;}
const Type &front() const {return head->item;}
void push(const Type &);
void pop();
bool empty() const{
return head==0;
}
private:
QueueItem<Type> *head;
QueueItem<Type> *tail;
void destroy();
void copy_elems(const Queue&);
};
#include "queue.cpp"
#endif

//queue.cpp
#include "stdafx.h"
template<class Type> void Queue<Type>::destroy()
{
while(!empty())
pop();
}
template <class Type> void Queue<Type>::pop()
{
QueueItem<Type> *p=head;
head=head->next;
delete p;
}
template <class Type> void Queue<Type>::push(const Type &val)
{
QueueItem<Type> *pt=new QueueItem<Type>(val);
if(empty())
head=tail=pt;
else{
tail->next=pt;
tail=pt;
}
}
template <class Type> void Queue<Type>::copy_elems(const Queue &orig)
{
for(QueueItem<Type> *pt=orig.head;pt!=0;pt=pt->next)
push(pt->item);
}
template <class Type> Queue<Type>& Queue<Type>::operator=(const Queue &orig)
{
destroy();
copy_elems();
return *this;
}

------------------------------------------------------------------------------------------------
//queue.h
#ifndef QUEUE_H
#define QUEUE_H
template<class Type>class Queue;
template<class Type> class QueueItem{
friend class Queue<Type>;
QueueItem(const Type &t):item(t),next(0){}
Type item;
QueueItem *next;
};
template<class Type>class Queue{
public:
Queue():head(0),tail(0){}
Queue(const Queue &Q):head(0),tail(0){copy_elems(Q);}
Queue& operator=(const Queue&);
~Queue(){destroy();}
Type &front() {return head->item;}
const Type &front() const {return head->item;}
void push(const Type &);
void pop();
bool empty() const{
return head==0;
}
private:
QueueItem<Type> *head;
QueueItem<Type> *tail;
void destroy();
void copy_elems(const Queue&);
};
//#include "queue.cpp"
#endif

//queue.cpp
#include "stdafx.h"
#include "queue.h"
template<class Type> void Queue<Type>::destroy()
{
while(!empty())
pop();
}
template <class Type> void Queue<Type>::pop()
{
QueueItem<Type> *p=head;
head=head->next;
delete p;
}
template <class Type> void Queue<Type>::push(const Type &val)
{
QueueItem<Type> *pt=new QueueItem<Type>(val);
if(empty())
head=tail=pt;
else{
tail->next=pt;
tail=pt;
}
}
template <class Type> void Queue<Type>::copy_elems(const Queue &orig)
{
for(QueueItem<Type> *pt=orig.head;pt!=0;pt=pt->next)
push(pt->item);
}
template <class Type> Queue<Type>& Queue<Type>::operator=(const Queue &orig)
{
destroy();
copy_elems();
return *this;
}

我的问题是为什么在cpp中include "queue.h"后可以运行正确;但是如果在头文件queue.h中include "queue.cpp"会出现很多错误呢?
...全文
672 11 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
hunterzone 2013-06-27
  • 打赏
  • 举报
回复
http://zhidao.baidu.com/question/146558179.html
是想定义在源文件吗?
1.这是不允许的,因为模板类的成员函数的定义,是一种不完整的定义.
2.由于编译器不知道模板参数的具体类型,无法为其成员函数生成代码
3.编译器在成员函数的调用处,才最终知道如何生成代码.
max_min_ 2013-05-21
  • 打赏
  • 举报
回复
引用 6 楼 lm_whales 的回复:
似乎模板的声明和实现分开在某些情况下是允许的,不过基本上生么作用也不起,浪费时间多写一些代码而已。 因为,对于模板类,声明和实现,必须同时可见,才可以编译不出错。 对于单纯的模板函数,则一点作用也没有。 曾经有人,为了版权,为了实现代码的保密。 为了把使用和模板分开编译,设法把模板类的声明和实现进行分离, 结果,这种违背客观规律的行为,丝毫作用也起不到。 最终也没有那个编译器,能够达到他的目的。 因为模板,只有使用的时候才知道,具体的数据类型,必须编译为使用该类型的模板参数的实现。 在用户没有使用模板的时候,任何人,任何编译器,都不能预测模板函数,和模板类的模板参数类型。 分离编译,唯一可以实现的是,接口和实现分离,声明处实现接口定义,实现处编写模板的实现代码。 接口看起来更清晰,但这是以实现代码,更复杂,更难写,更难懂为代价的,是得不偿失的。 所以标准库里的代码,大部分还是,实现和声明在一起的。真正分离实现的很少。 实际上,大家编写模板,也多半不会把声明和实现分离。 而且模板的代码必须,是实例化处(即引用处)可见的,这要求实现处,也要包含到应用处(#include“*.cpp”),这和大家的习惯严重不符。 所以分离实现的模板,好处不大,害处不小,这个很没有必要学,知道有这么回事就行了。
++ 涨见识了
turing-complete 2013-05-21
  • 打赏
  • 举报
回复
引用 7 楼 diaolingle 的回复:
[quote=引用 6 楼 lm_whales 的回复:] 似乎模板的声明和实现分开在某些情况下是允许的,不过基本上生么作用也不起,浪费时间多写一些代码而已。 因为,对于模板类,声明和实现,必须同时可见,才可以编译不出错。 对于单纯的模板函数,则一点作用也没有。 曾经有人,为了版权,为了实现代码的保密。 为了把使用和模板分开编译,设法把模板类的声明和实现进行分离, 结果,这种违背客观规律的行为,丝毫作用也起不到。 最终也没有那个编译器,能够达到他的目的。 因为模板,只有使用的时候才知道,具体的数据类型,必须编译为使用该类型的模板参数的实现。 在用户没有使用模板的时候,任何人,任何编译器,都不能预测模板函数,和模板类的模板参数类型。 分离编译,唯一可以实现的是,接口和实现分离,声明处实现接口定义,实现处编写模板的实现代码。 接口看起来更清晰,但这是以实现代码,更复杂,更难写,更难懂为代价的,是得不偿失的。 所以标准库里的代码,大部分还是,实现和声明在一起的。真正分离实现的很少。 实际上,大家编写模板,也多半不会把声明和实现分离。 而且模板的代码必须,是实例化处(即引用处)可见的,这要求实现处,也要包含到应用处(#include“*.cpp”),这和大家的习惯严重不符。 所以分离实现的模板,好处不大,害处不小,这个很没有必要学,知道有这么回事就行了。
单纯写在头文件中会导致头文件比较臃肿[/quote] C++ 模板 不支持头文件分离。 这下您该安心了。
lm_whales 2013-05-21
  • 打赏
  • 举报
回复
单纯写在头文件中会导致头文件比较臃肿. 难道比分离实现的,实现代码还用臃肿看吗??? 那么也别存放到。 .cxx,.cpp 里 另外起一个扩展名吧,比如微软的.inl 如果类过于复杂,那就别用一个类实现。 整个C++标准库中的类库,主要是STL代码,也不是很臃肿呀。头文件都不大呀。
diaolingle 2013-05-20
  • 打赏
  • 举报
回复
引用 6 楼 lm_whales 的回复:
似乎模板的声明和实现分开在某些情况下是允许的,不过基本上生么作用也不起,浪费时间多写一些代码而已。 因为,对于模板类,声明和实现,必须同时可见,才可以编译不出错。 对于单纯的模板函数,则一点作用也没有。 曾经有人,为了版权,为了实现代码的保密。 为了把使用和模板分开编译,设法把模板类的声明和实现进行分离, 结果,这种违背客观规律的行为,丝毫作用也起不到。 最终也没有那个编译器,能够达到他的目的。 因为模板,只有使用的时候才知道,具体的数据类型,必须编译为使用该类型的模板参数的实现。 在用户没有使用模板的时候,任何人,任何编译器,都不能预测模板函数,和模板类的模板参数类型。 分离编译,唯一可以实现的是,接口和实现分离,声明处实现接口定义,实现处编写模板的实现代码。 接口看起来更清晰,但这是以实现代码,更复杂,更难写,更难懂为代价的,是得不偿失的。 所以标准库里的代码,大部分还是,实现和声明在一起的。真正分离实现的很少。 实际上,大家编写模板,也多半不会把声明和实现分离。 而且模板的代码必须,是实例化处(即引用处)可见的,这要求实现处,也要包含到应用处(#include“*.cpp”),这和大家的习惯严重不符。 所以分离实现的模板,好处不大,害处不小,这个很没有必要学,知道有这么回事就行了。
单纯写在头文件中会导致头文件比较臃肿
lm_whales 2013-05-20
  • 打赏
  • 举报
回复
似乎模板的声明和实现分开在某些情况下是允许的,不过基本上生么作用也不起,浪费时间多写一些代码而已。 因为,对于模板类,声明和实现,必须同时可见,才可以编译不出错。 对于单纯的模板函数,则一点作用也没有。 曾经有人,为了版权,为了实现代码的保密。 为了把使用和模板分开编译,设法把模板类的声明和实现进行分离, 结果,这种违背客观规律的行为,丝毫作用也起不到。 最终也没有那个编译器,能够达到他的目的。 因为模板,只有使用的时候才知道,具体的数据类型,必须编译为使用该类型的模板参数的实现。 在用户没有使用模板的时候,任何人,任何编译器,都不能预测模板函数,和模板类的模板参数类型。 分离编译,唯一可以实现的是,接口和实现分离,声明处实现接口定义,实现处编写模板的实现代码。 接口看起来更清晰,但这是以实现代码,更复杂,更难写,更难懂为代价的,是得不偿失的。 所以标准库里的代码,大部分还是,实现和声明在一起的。真正分离实现的很少。 实际上,大家编写模板,也多半不会把声明和实现分离。 而且模板的代码必须,是实例化处(即引用处)可见的,这要求实现处,也要包含到应用处(#include“*.cpp”),这和大家的习惯严重不符。 所以分离实现的模板,好处不大,害处不小,这个很没有必要学,知道有这么回事就行了。
buyong 2013-05-18
  • 打赏
  • 举报
回复
通常来说,模版的实现都是放在.h文件中的。并且现在几乎所有的商用代码都是这么做的。比如stl, boost,还要很多开源软件。 理论上说,似乎模版的声明和实现分开在某些情况下是允许的,并且还有特殊用处。不过我没达到那个高度。而且好像并不实用。
luotuo44 2013-05-18
  • 打赏
  • 举报
回复
模板的声明和实现都应该放到同一个文件里面,不能像函数或者类那样分开放。 把类或者函数的声明和实现分开放,是为了避免在链接的时候出现重定义现象。而模板需要实例化,并且这个工作是在编译阶段完成。如果分开放了,那么编译的时候,就难于对模板进行实例化。
rxin423355541 2013-05-17
  • 打赏
  • 举报
回复
vc的话将queue.cpp的两个属性都改为标头文件
大尾巴猫 2013-05-17
  • 打赏
  • 举报
回复
模板类的声明和实现不能分开的吧。 最好都放在.h文件中
liaolianbing 2013-05-17
  • 打赏
  • 举报
回复
哪有人include cpp文件的啊,都是包含头文件啊

65,186

社区成员

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

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