我写了一个findDialog,它找到了搜索到的文本。当我发出make
命令时,它返回
g++ -Wl,-O1 -o findDialog FindDialog.o main.o moc_FindDialog.o -L/usr/lib -lQtGui -lQtCore -lpthread
moc_FindDialog.o: In function `FindDialog::findClicked()':
moc_FindDialog.cpp:(.text+0x20): multiple definition of `FindDialog::findClicked()'
FindDialog.o:FindDialog.cpp:(.text+0x30): first defined here
moc_FindDialog.o: In function `FindDialog::enableFindButton(QString const&)':
moc_FindDialog.cpp:(.text+0x50): multiple definition of `FindDialog::enableFindButton(QString const&)'
FindDialog.o:FindDialog.cpp:(.text+0x0): first defined here
collect2: ld returned 1 exit status
make: *** [findDialog] Error 1
我已经搜索了几个小时的问题,但我无法理解问题源于什么。
什么可能导致multiple definition of
错误?
答案 0 :(得分:18)
通常在方法定义包含在多个翻译单元中时也会发生,也称为目标文件。后来,当链接器组合这些目标文件时,它发现同一方法有多个定义,并抱怨因为它不知道使用哪一个。以下是如何引入此错误的简单示例:
头文件header.hpp
包含方法声明及其定义:
class foo {
public:
void bar ();
};
void foo::bar ()
{
}
有两个源文件source1.cpp和source2.cpp都包含该文件:
source1.cpp
:
#include "header1.hpp"
int example1()
{
foo f;
f.bar ();
}
...和source2.cpp
:
#include "header1.hpp"
int main ()
{
foo f;
f.bar ();
f.bar ();
}
然后,分别编译两个文件并将它们链接在一起。例如:
g++ -c source1.cpp source1.o
g++ -c source2.cpp source2.o
g++ -o a.out source1.o source2.o
这会给你一个你在问题中描述的链接器错误,因为方法foo::bar
在source1和source2对象中出现两次。链接器不知道使用哪一个。
这个问题有两种常见的解决方案:
解决方案#1 - 将该方法内联。
通过使用inline
关键字声明该方法,编译器将内联整个方法,或者如果决定不这样做,它将生成匿名方法(相同的方法,但给定的目标文件具有一些唯一的名称),所以目标文件中不会有冲突。例如:
class foo {
public:
void bar ();
};
inline void foo::bar ()
{
}
解决方案#2 - 在另一个源文件中定义(实现)该方法,以便它在整个程序中只出现一次。例如:
header1.hpp
:
class foo {
public:
void bar ();
};
header1.cpp
:
#include "header1.hpp"
void foo::bar ()
{
}
要决定是否内联,您必须知道(或至少猜测)调用此函数是否比在整个程序中复制/内联此代码更昂贵。内联代码通常会使您的程序更大并增加编译时间。但它并不一定能让它更快。另外,在源文件中定义不会导致使用该函数重新编译所有源文件,而只会重新编译具有定义的源文件,然后重新链接。许多程序员都对C ++内联很疯狂,却没有真正理解它如何影响程序。我建议在源文件中使用定义并仅在调用该函数成为性能瓶颈时使其内联,否则将其内联将修复它。
希望它有所帮助。快乐的编码!
答案 1 :(得分:5)
在头文件中编写函数定义,然后在项目的多个#include
中.cpp
这些头文件。与流行的误解相反,标题保护不保护您免受此攻击。
只在标题中写下以下内容:
将其他所有内容放在“源文件”中。
答案 2 :(得分:1)
Vlad Lazarenko的回答很好。
我只是添加了在使用QT / C ++时遇到的另一种可能性:
声明插槽时,不需要编写定义(实现),否则会出错:多重定义
答案 3 :(得分:0)
根据错误消息中的文件名判断,您有一些模拟测试夹具作为TDD的一部分和一些真实代码。链接器确实报告了相当清楚的问题 - 我在这里重新格式化了信息,以便通过删除部分信息来更加清晰:
moc_FindDialog.cpp: multiple definition of `FindDialog::findClicked()'
FindDialog.cpp: first defined here
moc_FindDialog.cpp: multiple definition of `FindDialog::enableFindButton(QString const&)'
FindDialog.cpp: first defined here
这清楚地表明链接器首先遇到moc_FindDialog.cpp
中的每个函数定义,然后遇到FindDialog.cpp
中的第二个定义。
我认为您需要仔细查看moc_FindDialog.cpp
中的模拟测试夹具,并确定复制这两个函数的原因。或者,也许你不应该在一个程序中链接模拟函数和实际函数 - 这两个源文件根本不是要链接到一个程序中。