HOWTO · C++

修復 C++ 中一個函式的多重定義錯誤

本文是關於 C++ 中多函式定義錯誤的解決方法。

這篇文章是關於 C++ 中經常出現的錯誤的解決方法,即函式的多個定義

修復 C++ 中的 multiple definitions of a function 錯誤

這種錯誤通常是在我們試圖分離函式原型和它的定義時引起的。因此,建議你將原型和定義分開放在不同的檔案中,並相應地包含該檔案。

參考下面的例子來理解這個問題。

示例程式碼(file1.cpp):

// file1.cpp
#include <iostream>
using namespace std;

class classB {
  friend void f1();

 public:
  classB(int i = 1, int j = 2) : a(i), b(j) {
    cout << "Hello from constructor\n";
  }

 private:
  int a;
  int b;
  void printfun() { cout << "a=" << a << endl << "b=" << b << endl; }
};
void f1() {  // ERROR HERE
  cout << "f1 start" << endl;
  classB tmp(3, 5);
  tmp.printfun();
  cout << "f1 end" << endl;
}

示例程式碼(main.cpp):

// main.cpp
#include <iostream>

#include "file1.cpp"
using namespace std;

int main() {
  cout << "calling function" << endl;
  f1();
  cout << "exit from main" << endl;
  return 0;
}

這就是在你的情況下發生的事情。由於 file1.cpp 檔案中的 #includefile1.cppmain.cpp 都包含 f1() 的定義,並且連結器不知道在你的檔案中使用哪一個程式並抱怨它。

解決方案是從 main.cpp 中刪除包含 f1() 定義的 CPP 檔案,並在單獨的標頭檔案中包含 f1() 的宣告,並將其包含在 main.cpp 中。編譯器將處理 f1() 的宣告,而連結器將僅依賴 file1.cpp 中的 f1() 定義。

示例程式碼(file1.h):

// file1.h
#include <iostream>

class classB {
  friend void f1();

 public:
  classB(int i = 1, int j = 2) : a(i), b(j) {
    std::cout << "Hello from constructor\n";
  }

 private:
  int a;
  int b;
  void printfun() { std::cout << "a=" << a << endl << "b=" << b << std::endl; }
};

示例程式碼(file1.cpp):

// file1.cpp
#include "file1.h"
using namespace std;
void f1() {
  cout << "f1 start" << endl;
  classB tmp(5, 6);
  tmp.printfun();
  cout << "f1 end" << endl;
}

示例程式碼(main.cpp):

// main.cpp
#include <iostream>

#include "file1.h"
using namespace std;

int main() {
  cout << "calling function" << endl;
  f1();
  cout << "exit from main" << endl;
  return 0;
}

讓我們從標頭檔案 file1.h 開始。標頭檔案包含所有內容的定義,如函式定義、任何結構或類定義或任何常量定義。

這個 .h 副檔名告訴編譯器不要編譯這個檔案。它就像一個文字檔案,任何人都可以閱讀。

這意味著標頭檔案是一個文件檔案。如果以後有程式設計師想使用某些函式,只需要檢查函式的原型,不需要詳細介紹函式定義。

最後,模板程式碼也應該在標頭檔案中。

CPP 檔案現在定義了在標頭檔案中宣告的函式。這告訴編譯器該檔案將被編譯並轉換為二進位制檔案。

你的程式碼的完整性將受到保護,未經你的許可,任何人都不能修改它。這意味著這種程式碼分離也確保了程式碼檔案的安全性。

這種技術背後的另一個原因是便攜性。例如,你編寫了一個二進位制搜尋程式碼,以後可以在許多其他程式中使用。

如果你有這些單獨的函式檔案,則可以在任何其他專案中輕鬆使用這些函式。

最後,主檔案只包含主函式,並在頂部包含標頭檔案。這個檔案只包含主函式,它只呼叫所有函式,沒有別的。