如何查找函数的多个定义

ste*_*kka 5 c++ linker qt

我写了一个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
Run Code Online (Sandbox Code Playgroud)

我已经搜索了几个小时的问题,但我无法理解问题源于什么.什么可能导致multiple definition of错误?

小智 20

当方法定义包含在多个翻译单元中时,通常会发生这种情况,也称为目标文件.后来,当链接器组合这些目标文件时,它发现同一方法有多个定义,并抱怨因为它不知道使用哪一个.这是一个如何引入此错误的简单示例:

具有header.hpp方法声明及其定义的头文件:

class foo {
public:
  void bar ();
};

void foo::bar ()
{
}
Run Code Online (Sandbox Code Playgroud)

并且有两个源文件source1.cpp和source2.cpp都包含该文件:

source1.cpp:

#include "header1.hpp"
int example1()
{
  foo f;
  f.bar ();
}
Run Code Online (Sandbox Code Playgroud)

......和source2.cpp:

#include "header1.hpp"
int main ()
{
  foo f;
  f.bar ();
  f.bar ();
}
Run Code Online (Sandbox Code Playgroud)

然后,分别编译两个文件并将它们链接在一起.例如:

g++ -c source1.cpp source1.o
g++ -c source2.cpp source2.o
g++ -o a.out source1.o source2.o
Run Code Online (Sandbox Code Playgroud)

这将为您提供您在问题中描述的链接器错误,因为方法foo::bar在source1和source2对象中都出现两次.链接器不知道使用哪一个.

这个问题有两种常见的解决方案:

解决方案#1 - 将该方法内联.

通过使用inline关键字声明该方法,编译器将内联整个方法,或者,如果它决定不这样做,它将生成匿名方法(相同的方法,但对于给定的目标文件具有一些唯一的名称),因此对象中不会有冲突文件.例如:

class foo {
public:
  void bar ();
};

inline void foo::bar ()
{
}
Run Code Online (Sandbox Code Playgroud)

解决方案#2 - 在另一个源文件中定义(实现)该方法,以便它在整个程序中只出现一次.例如:

header1.hpp:

class foo {
public:
  void bar ();
};
Run Code Online (Sandbox Code Playgroud)

header1.cpp:

#include "header1.hpp"
void foo::bar ()
{
}
Run Code Online (Sandbox Code Playgroud)

要决定是否内联,您必须知道(或至少猜测)调用此函数是否比在整个程序中复制/内联此代码更昂贵.内联代码通常会使您的程序更大并增加编译时间.但它并不一定能让它更快.另外,在源文件中定义不会导致使用该函数重新编译所有源文件,而只会重新编译具有定义的源文件,然后重新链接.许多程序员都对C++内联很疯狂,却没有真正理解它如何影响程序.我建议在源文件中使用定义并仅在调用该函数成为性能瓶颈时使其内联,否则将其内联将修复它.

希望能帮助到你.快乐的编码!


Lig*_*ica 5

在头文件中编写函数定义,然后在项目#include中的多个.cpps中输入这些头文件.与流行的误解相反,标题守卫并不能保护你免受这种伤害.

在标题中仅写下以下内容:

  • 类定义
    • 可以包含成员函数的内联定义
  • 非成员变量声明
  • 非成员函数声明
  • 模板/内联函数定义

将其他所有内容放在"源文件"中.