头文件dlist.h的一部分定义为:
#ifndef __DLIST_H__
#define __DLIST_H__
#include <iostream>
class emptyList {};
template <typename T>
class Dlist {
public:
bool isEmpty() const;
private:
struct node {
node *next;
node *prev;
T *o;
};
node *first; // The pointer to the first node (NULL if none)
node *last; // The pointer to the last node (NULL if none)
};
#include "dlist.cpp"
#endif
当我创建这样的dlist.cpp文件时:
#include "dlist.h"
template <typename T>
bool Dlist<T>::isEmpty() const
{
return !first and !last;
}
我在第4行收到错误消息:重新定义'bool Dlist :: isEmpty()const'
如果我删除#include "dlist.h"
我在第4行得到错误:在'&lt;'之前的预期初始值设定项令牌
这里有什么帮助吗?有什么我做错了,不允许我从dlist.h文件中定义我的函数吗?谢谢。
答案 0 :(得分:7)
您必须将类模板的成员函数的实现放在头文件或标头包含的文件中。编译器需要访问此代码才能为任何给定类型T
实例化模板。
在您的情况下,问题似乎是您在.cpp
中包含标题,反之亦然。如果您真的想在单独的文件中保留声明和实现,我建议将实现的后缀从.cpp
更改为其他内容,例如.icpp
。某些构建系统可能会尝试使用.cpp
后缀的任何内容编译目标文件,这也会导致错误。
#include "dlist.h"
移除dlist.cpp
。dlist.cpp
重命名为dlist.icpp
。为什么?因为许多构建系统会自动将以.cpp
结尾的任何文件编译到目标文件中。许多程序员都认为.cpp
文件将编译成目标文件。dlist.icpp
中包含重新命名的dlist.h
,与dlis.cpp
目前相同。答案 1 :(得分:2)
头文件是为我定义的,我不允许以任何方式更改它
然后,您需要从#include "dlist.h"
中移除.cpp
指令(因为您已经 dlist.h
中的,从而创建了循环依赖),因此把所有东西都完全倒退了,因为给你的标题是愚蠢的!
.cpp
永远不会成为#included
。通常,如果一个必须将与模板相关的定义拆分到它们自己的文件中,它应该有一些其他扩展名。我强烈建议你和那个掌管这个任务的人谈谈,并解释他们的标题是愚蠢的,混乱的和非传统的。
答案 2 :(得分:1)
不要在头文件中使用#include "dlist.cpp"
,而是将函数定义移到dlist.h
。
答案 3 :(得分:1)
为什么在.h文件中包含.cpp文件?在99%的情况下,你不应该这样做。
只需添加您的代码
即可template <typename T>
bool Dlist<T>::isEmpty() const
{
return !first and !last;
}
而不是.cpp文件包含指令。
答案 4 :(得分:0)
删除#include "dlist.h"
,不要编译dlist.cpp本身。
您还可以使用this:
之类的内容因为dlist.h包含dlist.cpp并定义__DLIST_H__
:
#define __DLIST_H__
您可以将dlist.cpp修改为
#ifdef __DLIST_H__
template <typename T>
bool Dlist<T>::isEmpty() const
{
return !first and !last;
}
#endif
这样,如果您尝试编译dlist.cpp,则不会出现编译器错误。 但我跟其他答案一样,最好不要命名这个文件.cpp。