C++ 模板编程编译错误

pine_blue 2009-09-13 10:26:31
请教高手
我在学习C++的模板,练习一个例子程序时编译总报错如下错误,不知是什么回事:
1>Queue.cpp
1>d:\dev\mytest\opclass\queue.cpp(10) : error C2995: “void Queue<Type>::destroy(void)”: 函数模板已经定义
1> d:\dev\mytest\include\queue.h(57) : 参见“Queue<Type>::destroy”的声明
1>d:\dev\mytest\opclass\queue.cpp(18) : error C2995: “void Queue<Type>::pop(void)”: 函数模板已经定义
1> d:\dev\mytest\include\queue.h(44) : 参见“Queue<Type>::pop”的声明
1>d:\dev\mytest\opclass\queue.cpp(34) : error C2995: “void Queue<Type>::push(const Type &)”: 函数模板已经定义
1> d:\dev\mytest\include\queue.h(43) : 参见“Queue<Type>::push”的声明
1>d:\dev\mytest\opclass\queue.cpp(44) : error C2995: “void Queue<Type>::copy_item(const Queue<Type> &)”: 函数模板已经定义
1> d:\dev\mytest\include\queue.h(56) : 参见“Queue<Type>::copy_item”的声明
1>d:\dev\mytest\opclass\queue.cpp(60) : error C2995: “void Queue<Type>::print(void)”: 函数模板已经定义
1> d:\dev\mytest\include\queue.h(50) : 参见“Queue<Type>::print”的声明


Queue.h文件:
#ifndef _QUEUE_H_
#define _QUEUE_H_

template <typename Type> class Queue;

template <typename Type>
class QueueItem
{
friend class Queue<Type>;
QueueItem( const Type& t ):value(t),next(0) {}
Type value;
QueueItem* next;
};

template <typename Type>
class Queue
{
public:
Queue():head(0),tail(0) {}

Queue( const Queue& Q ):head(0),tail(0)
{
copy_item(Q);
}

~Queue()
{
destroy();
}

Type& front()
{
return head->value;
}

const Type& front() const
{
return head->value;
}

void push( const Type& );
void pop();
bool empty() const
{
return head == 0;
}

void print();

protected:
private:
QueueItem<Type>* head;
QueueItem<Type>* tail;
void copy_item( const Queue& );
void destroy();
};
#include "Queue.cpp"
#endif


Queue.cpp文件:
#include "Queue.h"

template <typename Type>
void Queue<Type>::destroy()
{
while ( !empty() )
{
pop();
}
}

template <typename Type>
void Queue<Type>::pop()
{
QueueItem<Type> *ptr = head;
head = head->next;
delete ptr;
}

template <typename Type>
void Queue<Type>::push( const Type& t )
{
QueueItem<Type> *ptr = new QueueItem(t);

if ( empty() )
{
head = tail = ptr;
}
else
{
tail->next = ptr;
tail = tail->next;
}
}

template <typename Type>
void Queue<Type>::copy_item( const Queue& Q )
{
QueueItem<Type> *ptr = Q.head;
for ( ; ptr ; ptr++ )
{
push( ptr->value );
}
}

template <typename Type>
void Queue<Type>::print()
{
while( !empty() )
{
cout << head->value << endl;
}
}
...全文
588 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
tengerye 2011-02-07
  • 打赏
  • 举报
回复
还有一种方法:在.h文件中不包含.cpp;在main函数里#include .cpp也可以
zhangdakun 2009-10-25
  • 打赏
  • 举报
回复
顶起,用到了。
pine_blue 2009-09-17
  • 打赏
  • 举报
回复
谢谢了,终于弄明白了
但是如果我想把Queue这个类编译到一个静态库里面,那么就必须编译Queue.cpp,这时候该怎么解决重复定义的问题?估计只能把定义和声明放到一个文件里
[Quote=引用 16 楼 cphj 的回复:]
查了一些资料,终于弄明白了

原来C++ Primer是采用这样的技术让模板定义和实现分离

1. 在Queue.h文件的确写有#include "Queue.cpp"(这是对的)
2. 而建立的工程里面,并不把Queue.cpp包含进来(放在磁盘目录下,但别加入工程),也就是Queue.cpp并不直接参与编译链接,只有main()参加编译,
3. 在main()所在的文件中,#include "Queue.h"

由于1和3的效果,使分离的模板定义和实现合并到了main()所在的文件中
而由于Queue.cpp本身不直接编译(仅间接参与main()所在的文件的编译),所以也不会出现重定义错误

你之所以在windows下用命令行中用nmake可以编译成功,是因为他的makefile文件里面就是按上述要求写的,即makefile指明只编译main()所在的文件

[/Quote]
coolcoffee4051982 2009-09-14
  • 打赏
  • 举报
回复
顶了,学习啦
mstlq 2009-09-14
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 cphj 的回复:]
查了一些资料,终于弄明白了

原来C++ Primer是采用这样的技术让模板定义和实现分离

1. 在Queue.h文件的确写有#include "Queue.cpp"(这是对的)
2. 而建立的工程里面,并不把Queue.cpp包含进来(放在磁盘目录下,但别加入工程),也就是Queue.cpp并不直接参与编译链接,只有main()参加编译,
3. 在main()所在的文件中,#include "Queue.h"

由于1和3的效果,使分离的模板定义和实现合并到了main()所在的文件中
而由于Queue.cpp本身不直接编译(仅间接参与main()所在的文件的编译),所以也不会出现重定义错误

你之所以在windows下用命令行中用nmake可以编译成功,是因为他的makefile文件里面就是按上述要求写的,即makefile指明只编译main()所在的文件

[/Quote]

确实如此,我觉得这个实现方式挺恶心的>_<
cphj 2009-09-14
  • 打赏
  • 举报
回复
查了一些资料,终于弄明白了

原来C++ Primer是采用这样的技术让模板定义和实现分离

1. 在Queue.h文件的确写有#include "Queue.cpp"(这是对的)
2. 而建立的工程里面,并不把Queue.cpp包含进来(放在磁盘目录下,但别加入工程),也就是Queue.cpp并不直接参与编译链接,只有main()参加编译,
3. 在main()所在的文件中,#include "Queue.h"

由于1和3的效果,使分离的模板定义和实现合并到了main()所在的文件中
而由于Queue.cpp本身不直接编译(仅间接参与main()所在的文件的编译),所以也不会出现重定义错误

你之所以在windows下用命令行中用nmake可以编译成功,是因为他的makefile文件里面就是按上述要求写的,即makefile指明只编译main()所在的文件
pine_blue 2009-09-14
  • 打赏
  • 举报
回复
这个倒没有提到,我是在vs2005下编译的。你是不是有这方面的经验,模板分离编译不会通过?
[Quote=引用 13 楼 pengzhixi 的回复:]
教程上这个实例用的啥编译器呢?
[/Quote]
pengzhixi 2009-09-14
  • 打赏
  • 举报
回复
教程上这个实例用的啥编译器呢?
pine_blue 2009-09-14
  • 打赏
  • 举报
回复
但是按照教程的说法,定义和声明分开文件是可行的,而且这个例子就是分离的
[Quote=引用 10 楼 pengzhixi 的回复:]
模板别分离编译
[/Quote]
pine_blue 2009-09-14
  • 打赏
  • 举报
回复
这个是没问题,我现在是想把定义和声明分开文件放,呵呵
[Quote=引用 1 楼 yang_e_2009 的回复:]
把函数定义写在头文件中试试
[/Quote]
pengzhixi 2009-09-14
  • 打赏
  • 举报
回复
模板别分离编译
pine_blue 2009-09-14
  • 打赏
  • 举报
回复
分析得有一定道理,也感觉是这里有问题,但在头文件中包含.cpp文件是按照例子程序写的,如果不包含,.cpp可以编过,但是连接main时会报错:destroy()是无法解析的外部符号
[Quote=引用 6 楼 zhoudaxia 的回复:]
  你编译的是Queue.cpp,这个文件中有一个#include "Queue.h",但Queue.h中又有一个#include "Queue.cpp",导致Queue.cpp通过Queue.h间接地包含Queue.cpp自己,当然会出现重复定义了
[/Quote]
pine_blue 2009-09-14
  • 打赏
  • 举报
回复
去掉只能编译Queue.cpp通过,但是编译连接main就报错,destroy()是无法解析的外部符号
[Quote=引用 5 楼 cphj 的回复:]
};
#include "Queue.cpp"
#endif

在Queue.h中有一行居然包含了cpp文件,去掉之后在VC2008下编译通过


[/Quote]
pine_blue 2009-09-14
  • 打赏
  • 举报
回复
在Queue.h中包含Queue.cpp是因为要在main函数中用到这个类,否则编译不过。上面说的编译错误是在编译Queue.cpp文件时报的。

main函数:
#include "Queue.h"

int main( int argc, char **argv )
{
try
{
Queue<string> que;
//que.push( "shix" );
//que.push( "zhuy" );
//que.push( "shxs" );
//que.push( "zhuh" );
//que.print();

//Queue<string> q_str = que;

}
catch (exception* e)
{
cout << "There is an exception!" << e->what() << endl;
delete e;
}

return 0;
}
pine_blue 2009-09-14
  • 打赏
  • 举报
回复
我看的是C++ Primer第4版,刚上网把源文件下下来,我把他的cpp和h文件放到我的工程里面来也是报同样的错,他的目录里面有一个makefile文件,在windows下用命令行中用nmake可以编译成功
我现在想把这两个文件放到我的vs2005工程里面,是不是声明和定义只能放到一个文件里?
Dave888Zhou 2009-09-13
  • 打赏
  • 举报
回复
你编译的是Queue.cpp,这个文件中有一个#include "Queue.h",但Queue.h中又有一个#include "Queue.cpp",导致Queue.cpp通过Queue.h间接地包含Queue.cpp自己,当然会出现重复定义了
cphj 2009-09-13
  • 打赏
  • 举报
回复
};
#include "Queue.cpp"
#endif

在Queue.h中有一行居然包含了cpp文件,去掉之后在VC2008下编译通过

mengde007 2009-09-13
  • 打赏
  • 举报
回复
把main函数一块贴出来;
wanjingwei 2009-09-13
  • 打赏
  • 举报
回复
放一个文件里
jkx01whg 2009-09-13
  • 打赏
  • 举报
回复
Queue.h文件:
#ifndef _QUEUE_H_
#define _QUEUE_H_
.....
......
void destroy();
};
#include "Queue.cpp" //这里为什么要包含定义文件呢?
#endif
加载更多回复(1)

64,646

社区成员

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

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