簡體   English   中英

如何查找函數的多個定義

[英]How to find the multiple definitions of a function

我寫了一個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

當方法定義包含在多個翻譯單元中時,通常會發生這種情況,也稱為目標文件。 后來,當鏈接器組合這些目標文件時,它發現同一方法有多個定義,並抱怨因為它不知道使用哪一個。 這是一個如何引入此錯誤的簡單示例:

頭文件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 ++內聯很瘋狂,卻沒有真正理解它如何影響程序。 我建議在源文件中使用定義並僅在調用該函數成為性能瓶頸時使其內聯,否則將其內聯將修復它。

希望能幫助到你。 快樂的編碼!

在頭文件中編寫函數定義,然后在項目的多個.cpp #include這些頭文件。 與流行的誤解相反,標題守衛並不能保護你免受這種傷害。

在標題中僅寫下以下內容:

  • 類定義
    • 可以包含成員函數的內聯定義
  • 非成員變量聲明
  • 非成員函數聲明
  • 模板/內聯函數定義

將其他所有內容放在“源文件”中。

Vlad Lazarenko的回答很好。

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

聲明一個插槽時,不需要編寫定義(實現),否則會出現錯誤:多個定義

從錯誤消息中的文件名判斷,您可以將一些模擬測試裝置作為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中的模擬測試夾具,並確定復制這兩個函數的原因。 或者,也許您不應該將模擬函數和實際函數鏈接到單個程序中 - 這兩個源文件根本不打算鏈接到單個程序中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM