2013-01-20 34 views
2

如果您定義了一個類來做某件事,那麼您只需要包含一個包含其方法原型的頭文件(.h文件),但是您不必包括意味着.cpp文件必須有一個名字等同於它的頭文件,使編譯器將類文件本身(其中包含實際實現的類方法.cpp文件),C++編譯器如何知道類在哪裏

不名稱來找到.cpp文件?

OR

當編譯器遇到一個函數(方法)調用它去頭文件,並查看其是否已具雛形。然後它在內置函數中搜索實現,如果沒有發現它在當前目錄中的所有.cpp文件中搜索?

還是都假設不正確?

回答

2

編譯器只需要頭文件。但是所有的C++文件都需要編譯,所以鏈接器可以生成最終的二進制文件。

1

爲了生成一個程序,編譯器需要兩個。通常情況下,從C++到二進制文件的編譯分兩步進行,但首先將每個CPP文件(又名翻譯單元)轉換爲一個目標文件(主要包含機器碼和地址表)。然後,目標文件相互連接(鏈接),形成最終的可執行文件(需要使用地址表)。通常,在頭文件中,你會說「有一個帶有這些參數和返回值的函數」。在目標文件中,對該函數的調用將被記錄爲對該函數的引用。最後,在鏈接時,該引用將與其他對象文件必須提供的函數的實際地址一起解析。

4

文件名在C++中是不相關的。 鏈接器將所有的部分放在一起。所有你需要知道的東西,而事情的名稱意味着一點C++代碼。這就是的聲明類德­網絡的目的­妮­蒸發散:他們介紹了名稱,並且給編譯器足夠的信息來生成代碼:

file1.cpp:

int f(int, bool);   // declaration 

class Foo;    // class declaration 

class Bar { int g(); }; // class definition (implies declaration) 

int main() 
{ 
    Foo * p;    // OK, Foo * is a complete type, since we know that 
          // "Foo" denotes a class 

    // p->h();   // Error: We don't know what Foo actually is! 

    Bar b;    // OK, we know how size and alignment for Bar 

    int m = b.g();  // OK, we know what sort of function B::g() is 

    int n = f(50, true); // OK, we don't need to know what f does 

    return m + n; 
} 

當上面的代碼被編譯時,它將包含未解決的符號對於fB::g。只要一個(也是唯一一個)其他翻譯單元包含這些符號的定義,接頭可以解決這些問題和程序可以順利鏈接:

file2.cpp:

int f(int n, bool b) { return b ? n * 2 : 50 - n; } 

// include class definition here 
int Bar::g() { return f(sizeof(Bar), sizeof(int) == sizeof(char)); } 

的基本規則是,你可以聲明一個函數或類或定義一個類一個多次,只要你喜歡,但你只能定義一個函數和一個類成員函數。有一個例外:如果您將類成員函數的函數聲明爲inline,則實際上可以重複定義,前提是所有定義都是相同的。

這條規則的必然結果是,只要您只在一個單獨的翻譯單元中提供一次實際定義,就可以安全地將所有函數聲明和類定義放入一個頭文件並重復包含它。 (並且inline規則允許您在類定義中包含實際成員函數定義–與其聲明一起定義的成員函數隱含地爲inline。)

+1

+1獲得詳細答案。 – Macmade

+0

我不同意「文件名與C++無關」的說法。預處理器是該語言的一部分,'#include'在文件名方面的確談得最多(除非標準允許這是由實現定義的,我懷疑它)。 –

+0

@MichaelPrice:好的,你也必須給編譯器提供正確的文件名,否則編譯器甚至不會運行。我並不是說文件名是*不必要*。我只是說他們的價值觀並不重要:如果在構建中的任何地方用其他文件替換一個文件名,它仍然可以工作。 –

相關問題