如何查找函数的多个定义

时间:2021-08-16 17:09:09

I wrote a findDialog which finds the text searched. When I give make command,it returns

我写了一个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

I have searched the problem for hours, but I can not understand what the problem stems from. What can cause multiple definition of error?

我已经搜索了几个小时的问题,但我无法理解问题源于什么。什么可能导致错误的多重定义?

4 个解决方案

#1


18  

It usually happens when method definition is included in multiple translation units, also called as object files. Later, when linker is combining those object files, it finds out that there are multiple definitions of the same method, and complains because it doesn't know which one to use. Here is a simple example of how to introduce this error:

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

Have header file header.hpp with both method declaration and its definition:

头文件header.hpp包含方法声明及其定义:

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

void foo::bar ()
{
}

And have two source files source1.cpp and source2.cpp both including that file:

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

source1.cpp:

#include "header1.hpp"
int example1()
{
  foo f;
  f.bar ();
}

... and source2.cpp:

...和source2.cpp:

#include "header1.hpp"
int main ()
{
  foo f;
  f.bar ();
  f.bar ();
}

Then, compile two files separately and link them together. For example:

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

g++ -c source1.cpp source1.o
g++ -c source2.cpp source2.o
g++ -o a.out source1.o source2.o

That will give you a linker error you have described in your question, because method foo::bar appears twice, in both source1 and source2 objects. Linker doesn't know which one to use.

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

There are two common solutions to this problem:

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

Solution #1 - Have that method inlined.

解决方案#1 - 内联方法。

By declared that method with inline keyword, compiler will either inline the whole method or, if it decides not to, it will generate anonymous method (same method but with some unique name for a given object file), so there will be no conflicts in object files. For example:

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

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

inline void foo::bar ()
{
}

Solution #2 - Have definition (implementation) of that method in another source file, so that it appears only once in the whole program. For example:

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

header1.hpp:

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

header1.cpp:

#include "header1.hpp"
void foo::bar ()
{
}

To decide whether to inline or not, you have to know (or at least make a guess) whether calling this function is more expensive than having this code duplicated / inlined all over the program. Inlined code usually makes your program bigger and increases compilation time. But it doesn't necessarily make it faster. Plus, having definition in source file will not result in re-compilation of all source files using that function, but only re-compilation of the source file that has definition, and then re-linking. Many programmers are going crazy about C++ inlining without really understanding how it affects the program. I'd recommend going with the definition in a source file and making it inline only if calling that function becomes a performance bottleneck and otherwise having it inlined will fix it.

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

Hope it helps. Happy coding!

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

#2


4  

Writing function definitions in header files, and then #includeing these header files in multiple .cpps in your project. Contrary to popular misconception, header guards do not protect you from this.

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

Write only the following in headers:

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

  • Class definitions
    • May include inline definitions for member functions
    • 可以包含成员函数的内联定义

  • 可以包含成员函数的内联定义

  • Non-member variable declarations
  • 非成员变量声明

  • Non-member function declarations
  • 非成员函数声明

  • Template/inline function definitions
  • 模板/内联函数定义

Put everything else in "source files".

将其他所有内容放在“源文件”中。

#3


1  

Vlad Lazarenko's answer is good.

Vlad Lazarenko的回答很好。

I just add another possibility that I met when using QT/C++:

我只是添加了在使用QT / C ++时遇到的另一种可能性:

When you declare a slot, you don't need to write a definition (implementation), otherwise, you will get an error: multiple definition

声明一个插槽时,不需要编写定义(实现),否则会出现错误:多个定义

#4


0  

Judging from file names in the error messages, you have some mock test fixtures as part of TDD and some real code. The linker did report where the trouble is fairly clearly - I've reformatted the information here for extra clarity by removing part of the information:

从错误消息中的文件名判断,您有一些模拟测试夹具作为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

This clearly states that the linker first encountered each of the function definitions in moc_FindDialog.cpp, and then encountered the second definition in FindDialog.cpp.

这清楚地表明链接器首先遇到moc_FindDialog.cpp中的每个函数定义,然后在FindDialog.cpp中遇到第二个定义。

I think you need to look hard at the mock test fixture in moc_FindDialog.cpp and determine why those two functions are replicated. Or, maybe you are not supposed to link both the mock functions and the real functions in a single program - the two source files are simply not intended to be linked into a single program.

我认为您需要仔细查看moc_FindDialog.cpp中的模拟测试夹具,并确定复制这两个函数的原因。或者,也许你不应该在单个程序中链接模拟函数和实际函数 - 两个源文件根本不打算链接到单个程序中。

#1


18  

It usually happens when method definition is included in multiple translation units, also called as object files. Later, when linker is combining those object files, it finds out that there are multiple definitions of the same method, and complains because it doesn't know which one to use. Here is a simple example of how to introduce this error:

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

Have header file header.hpp with both method declaration and its definition:

头文件header.hpp包含方法声明及其定义:

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

void foo::bar ()
{
}

And have two source files source1.cpp and source2.cpp both including that file:

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

source1.cpp:

#include "header1.hpp"
int example1()
{
  foo f;
  f.bar ();
}

... and source2.cpp:

...和source2.cpp:

#include "header1.hpp"
int main ()
{
  foo f;
  f.bar ();
  f.bar ();
}

Then, compile two files separately and link them together. For example:

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

g++ -c source1.cpp source1.o
g++ -c source2.cpp source2.o
g++ -o a.out source1.o source2.o

That will give you a linker error you have described in your question, because method foo::bar appears twice, in both source1 and source2 objects. Linker doesn't know which one to use.

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

There are two common solutions to this problem:

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

Solution #1 - Have that method inlined.

解决方案#1 - 内联方法。

By declared that method with inline keyword, compiler will either inline the whole method or, if it decides not to, it will generate anonymous method (same method but with some unique name for a given object file), so there will be no conflicts in object files. For example:

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

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

inline void foo::bar ()
{
}

Solution #2 - Have definition (implementation) of that method in another source file, so that it appears only once in the whole program. For example:

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

header1.hpp:

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

header1.cpp:

#include "header1.hpp"
void foo::bar ()
{
}

To decide whether to inline or not, you have to know (or at least make a guess) whether calling this function is more expensive than having this code duplicated / inlined all over the program. Inlined code usually makes your program bigger and increases compilation time. But it doesn't necessarily make it faster. Plus, having definition in source file will not result in re-compilation of all source files using that function, but only re-compilation of the source file that has definition, and then re-linking. Many programmers are going crazy about C++ inlining without really understanding how it affects the program. I'd recommend going with the definition in a source file and making it inline only if calling that function becomes a performance bottleneck and otherwise having it inlined will fix it.

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

Hope it helps. Happy coding!

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

#2


4  

Writing function definitions in header files, and then #includeing these header files in multiple .cpps in your project. Contrary to popular misconception, header guards do not protect you from this.

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

Write only the following in headers:

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

  • Class definitions
    • May include inline definitions for member functions
    • 可以包含成员函数的内联定义

  • 可以包含成员函数的内联定义

  • Non-member variable declarations
  • 非成员变量声明

  • Non-member function declarations
  • 非成员函数声明

  • Template/inline function definitions
  • 模板/内联函数定义

Put everything else in "source files".

将其他所有内容放在“源文件”中。

#3


1  

Vlad Lazarenko's answer is good.

Vlad Lazarenko的回答很好。

I just add another possibility that I met when using QT/C++:

我只是添加了在使用QT / C ++时遇到的另一种可能性:

When you declare a slot, you don't need to write a definition (implementation), otherwise, you will get an error: multiple definition

声明一个插槽时,不需要编写定义(实现),否则会出现错误:多个定义

#4


0  

Judging from file names in the error messages, you have some mock test fixtures as part of TDD and some real code. The linker did report where the trouble is fairly clearly - I've reformatted the information here for extra clarity by removing part of the information:

从错误消息中的文件名判断,您有一些模拟测试夹具作为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

This clearly states that the linker first encountered each of the function definitions in moc_FindDialog.cpp, and then encountered the second definition in FindDialog.cpp.

这清楚地表明链接器首先遇到moc_FindDialog.cpp中的每个函数定义,然后在FindDialog.cpp中遇到第二个定义。

I think you need to look hard at the mock test fixture in moc_FindDialog.cpp and determine why those two functions are replicated. Or, maybe you are not supposed to link both the mock functions and the real functions in a single program - the two source files are simply not intended to be linked into a single program.

我认为您需要仔细查看moc_FindDialog.cpp中的模拟测试夹具,并确定复制这两个函数的原因。或者,也许你不应该在单个程序中链接模拟函数和实际函数 - 两个源文件根本不打算链接到单个程序中。