C++错误信息重定义函数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19965300/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C++ Error message redefinition of functions
提问by Hayden Coyle
I am using two stacks to implement a queue class. My header file looks like:
我正在使用两个堆栈来实现一个队列类。我的头文件看起来像:
#ifndef _MyQueue_h
#define _MyQueue_h
using namespace std;
template <typename T>
class MyQueue {
public:
MyQueue();
~MyQueue();
void enqueue(T element);
T peek();
void dequeue();
int size();
bool empty();
private:
int count;
stack<T> stk1;
stack<T> stk2;
};
# include "MyQueue.cpp"
# endif
And my cpp (implementation) file looks like:
我的 cpp(实现)文件如下所示:
#include <stack>
#include "MyQueue.h"
using namespace std;
template <typename T>
MyQueue<T>::MyQueue()
{
count = 0;
}
template <typename T>
MyQueue<T>::~ MyQueue()
{
}
template <typename T>
void MyQueue<T>::enqueue(T element)
{
stk1.push(element);
count ++;
}
(other functions omitted).
(省略其他功能)。
However, using Xcode 4.5, it keeps saying that my functions (MyQueue, ~MyQueue, enqueue, peek, etc.) are redefined. Can anyone help me to clarify where have I redefined them?
但是,使用 Xcode 4.5,它一直说我的函数(MyQueue、~MyQueue、enqueue、peek 等)被重新定义。谁能帮我澄清一下我在哪里重新定义了它们?
Thank you
谢谢
回答by john
You're trying something which I really don't like. It's a pretence.
你正在尝试我真的不喜欢的东西。这是一个幌子。
Remove #include "MyQueue.cpp"
, replace it with the content of MyQueue.cpp, delete the file MyQueue.cpp. Now everything will work.
删除#include "MyQueue.cpp"
,替换为 MyQueue.cpp 的内容,删除文件 MyQueue.cpp。现在一切都会好起来的。
You are trying to pretend the template code can be split into header file and implementation file. But because it can't you have to cheat by including the implementation file in the header file. It's less confusing if you don't cheat or pretend and just have one file, the header file, with everything in it.
您试图假装模板代码可以拆分为头文件和实现文件。但是因为它不能通过在头文件中包含实现文件来作弊。如果您不作弊或假装并且只有一个文件,即头文件,其中包含所有内容,则不会那么令人困惑。
The precise reason that you get a redefinition is that you are compiling your cpp file, which includes your header file, which includes your cpp file again. So the content of the cpp file gets compiled twice.
您获得重新定义的确切原因是您正在编译您的 cpp 文件,其中包括您的头文件,其中又包括您的 cpp 文件。所以 cpp 文件的内容被编译了两次。
回答by NeoGeetz
In C and C++, #include behaves like a copy and paste. Everytime you see
在 C 和 C++ 中,#include 的行为类似于复制和粘贴。每次看到
#include "file"
it should be treated as if you literally retyped the whole file in that one spot. So if you compile MyQueue.cpp, the preprocessor will prepend the contents of MyQueue.h, which itself tacks on a duplicate of MyQueue.cpp evidenced by
应该将其视为您真的在那个位置重新输入了整个文件。因此,如果您编译 MyQueue.cpp,预处理器将添加 MyQueue.h 的内容,该内容本身附加在 MyQueue.cpp 的副本上,由
#include "MyQueue.cpp"
and then follows the native content of MyQueue.cpp.
然后遵循 MyQueue.cpp 的本机内容。
So the result of
所以结果是
#include "MyQueue.cpp"
inside MyQueue.h, is the same as if you had written one big file with the contents of MyQueue.h, MyQueue.cpp and MyQueue.cpp again. (with the include of stack in there as well of course) That is why the compiler complained about functions getting redefined.
在 MyQueue.h 中,就像您再次使用 MyQueue.h、MyQueue.cpp 和 MyQueue.cpp 的内容编写了一个大文件一样。(当然也包含堆栈)这就是编译器抱怨函数被重新定义的原因。
The Duplicate inserted from the
从插入的重复项
#include "MyQueue.cpp"
might also contain the line
也可能包含该行
#include "MyQueue.h"
but I think the include guards (ifndef,endif) protected against a recursive expansion since that did not seem to be an issue.
但我认为包含保护 (ifndef,endif) 可以防止递归扩展,因为这似乎不是问题。
I would like to point out that putting all the implementation code and declaration code in the same file for templates is not the only solution, as others suggest.
You just have to remember that templates are generated at compile time and include them wherever they are needed. Like Aaron has pointed out, you can even force generate a template for a specific type or function so it's accessible to all units.
In this way, the definition of a function can be embedded in an arbitrary module and the rest of the modules won't complain that a function isn't defined.
I like to declare small templates and template interfaces in header files and put large implementations in special files that are just glorified headers. You could put some special extension like .tpp .cppt or whatever to remind yourself that it is code you have to include somewhere (which is what I do).
It is a suitable alternative to storing large implementations in header files that must be pasted around just to refer to the type (or function signature). And it works absolutely fine, for years now.
So for example, when I am ready to compile my big program, I might have a file called structures.cpp that I designate to implement lots of small structures I use, as well as instantiate all the templates for my project.
all the other .cpp files in the project need to include "mylib/template_structs.h" in order to create instances of templates and call functions with them. whereas structures.cpp only needs to include "mylib/template_structs.cppt" which in turn may include template_structs.h or else structures.cpp would have to include that as well first.
If structures.cpp calls all the functions that any other .cpp files would call for that template then we are done, if not, then you'd need the extra step of something like
template class mynamespace::queue<int> ;
to generate all the other definitions the rest of the project's modules would need.
我想指出,正如其他人所建议的那样,将所有实现代码和声明代码放在同一个模板文件中并不是唯一的解决方案。
您只需要记住模板是在编译时生成的,并将它们包含在需要的地方。就像Aaron 指出的那样,您甚至可以强制为特定类型或功能生成模板,以便所有单位都可以访问它。
通过这种方式,函数的定义可以嵌入到任意模块中,而其余模块不会抱怨函数未定义。
我喜欢在头文件中声明小模板和模板接口,并将大实现放在只是美化头文件的特殊文件中。你可以放一些特殊的扩展名,比如 .tpp .cppt 或其他任何东西来提醒自己这是你必须在某处包含的代码(这就是我所做的)。
它是将大型实现存储在头文件中的合适替代方案,这些头文件必须粘贴以引用类型(或函数签名)。它工作得很好,多年来。
例如,当我准备编译我的大程序时,我可能有一个名为structures.cpp 的文件,我指定它来实现我使用的许多小结构,并为我的项目实例化所有模板。
项目中的所有其他 .cpp 文件都需要包含“mylib/template_structs.h”,以便创建模板实例并使用它们调用函数。而structures.cpp 只需要包含“mylib/template_structs.cppt”,而后者又可能包含template_structs.h,否则structures.cpp 也必须首先包含它。
如果structures.cpp 调用任何其他.cpp 文件为该模板调用的所有函数,那么我们就完成了,如果没有,那么您需要额外的步骤,例如
template class mynamespace::queue<int> ;
生成项目其余模块所需的所有其他定义。
回答by Aaron McDaid
The problem is that, when compiling the cpp file, the cpp file includes the .h
file and then the .h
file includes the .cpp
file. Then you have twocopies of the cpp code in the same 'translation unit' at the same time.
问题是,在编译cpp文件时,cpp文件包含.h
文件,然后.h
文件包含.cpp
文件。然后,您在同一“翻译单元”中同时拥有两个cpp 代码副本。
But there are a few different solutions to this, it depends what your ultimate goal is.
但是对此有几种不同的解决方案,这取决于您的最终目标是什么。
The simplest, and most flexible solution is simply to remove all the template stuff from the
.cpp
file and put it into the.h
file instead. You might think this is bad design, you've probably been taught to keep declarations and definitions in separate files, but this is how templates are usually implemented. (Welcome to the weird and wonderful world of C++ templates!)But, perhaps these are to be 'private' templates, only to be used from one
.cpp
file. In that case, the best thing to do is simply to move everything from the.h
file into the.cpp
file.There is a third approach, which doesn't get enough attention in my opinion. First, remove the
#include "MyQueue.cpp"
from your.h
file, and recompile. It's quite possible that will just work for you. However, ifyour project has multiple.cpp
files, you might get linker errors aboutundefined reference to MyQueue<string> :: MyQueue()
. (wherestring
is replaced with whatever you are putting in your queue. These linker errors can be fixed by placingtemplate MyQueue<string>;
at the endof the file that has the definitions of the templates (yourMyQueue.cpp
). This means you have to do this once for each type that you plan to store in your queue, but you might see this as an advantage as it helps you remember which types are supported by your queue.
最简单、最灵活的解决方案是简单地从
.cpp
文件中删除所有模板内容并将其放入.h
文件中。您可能认为这是糟糕的设计,您可能已经被教导将声明和定义保存在单独的文件中,但这就是模板通常的实现方式。(欢迎来到奇妙而奇妙的 C++ 模板世界!)但是,也许这些是“私有”模板,只能从一个
.cpp
文件中使用。在这种情况下,最好的办法就是将.h
文件中的所有内容移动到.cpp
文件中。还有第三种方法,我认为它没有得到足够的关注。首先,
#include "MyQueue.cpp"
从.h
文件中删除,然后重新编译。这很可能只适合你。但是,如果您的项目有多个.cpp
文件,您可能会收到有关undefined reference to MyQueue<string> :: MyQueue()
. ( wherestring
替换为您放入队列中的任何内容。这些链接器错误可以通过放置template MyQueue<string>;
在具有模板定义的文件末尾(您的MyQueue.cpp
)来修复。这意味着您必须为每种类型执行一次您计划存储在您的队列中,但您可能认为这是一个优势,因为它可以帮助您记住您的队列支持哪些类型。
回答by XenoZergNid
when you include something it replaces the included file with the code within so when you call #include "MyQueue.cpp" it replaces that with the cpp file, then your cpp file redefines it. Getting rid of the line will fix it.
当您包含某些内容时,它会将包含的文件替换为其中的代码,因此当您调用 #include "MyQueue.cpp" 时,它会将其替换为 cpp 文件,然后您的 cpp 文件会重新定义它。摆脱这条线将解决它。