2016-06-14 65 views
0

我在頭文件中定義了一個類,並在同一頭文件中實現了它的功能。我沒有在函數定義中加入內聯關鍵字,因爲我認爲編譯器默認將它視爲內聯函數 - 但內聯只是編譯器的一個提示,對吧?如果編譯器由於其長度而不將其視爲內聯函數呢?我從來沒有在現實中得到錯誤信息'多重定義'。可以在頭文件中定義一個非常長的類函數成員?

struct tmp { 
    void print() { 
     ...(very long) 
    } 
}; 
+2

爲什麼?每次包含文件時,你是否真的希望編譯器能夠編譯所有代碼?什麼目的? – EJP

+0

編譯器不會這樣做,@ejp,假設程序員足夠勝任使用包括守衛。 –

+0

@EJP只是爲了好奇心,有時小功能變得越來越大...... –

回答

2

我並沒有把與函數定義inline關鍵字,因爲我覺得編譯器會認爲這是一個inline函數默認

是,在類的主體定義的成員函數隱inline。關鍵字不是必需的。

內聯只是提示編譯器吧?如果編譯器由於其長度而不將其視爲內聯函數呢?

是的,有點。實際上,inline關鍵字有兩個含義。

第一個是你正在想的那個,它暗示了優化器在調用站點的函數體中內聯代碼。正如你所說的那樣,這只是一個提示 - 如果優化器確定這樣做會使性能更悲觀(或者由於某些其他技術原因而無法內聯),則優化器可以自由地忽略此請求。 inline關鍵字的含義可以說是過時了。現在所有的優化編譯器都忽略了inline關鍵字,因爲他們的作者認爲他們的啓發式算法比編程者更聰明。這幾乎總是如此,通過內聯標記函數來嘗試和猜測優化器是毫無意義的。

內聯關鍵字的第二個含義是放寬單定義規則(ODR),使其對鏈接器可見的同一功能有多個定義是合法的。 (儘管鏈接器在這種情況下的行爲是一個實現細節,但大多數將只是任意選擇其中一個定義。當然,如果它們完全相同,哪一個當然是行得通的。)這個inline關鍵字的含義仍然是非常重要,並解釋了爲什麼它仍然在代碼中使用。

這就是您的代碼從中受益的含義。由於在類的主體中定義的成員函數被隱式標記爲內聯,所以您不會從鏈接器中獲得多重定義的符號錯誤。

如果你在頭文件中定義的功能,但類中的定義,換句話說,如果你做了這一點:

struct tmp { 
    void print(); 
}; 

void tmp::print() 
{ ... } 

那麼你將開始獲取多重定義的符號該頭文件包含在兩個或更多compilands中(,即,翻譯單元)。這是您需要在函數定義中添加inline關鍵字的地方,這不是因爲您希望編譯器「內聯」它,而是因爲您希望免除ODR。

+0

因此,對於只定義一次的小功能的'內聯'是沒有意義的? –

+0

@lw'inline'關鍵字的兩個含義不能很容易被拉開。將函數聲明標記爲內聯是沒有意義的,除非聲明和定義是相同的,所以您不能擁有隻定義一次的內聯函數。如果你在頭文件中定義了一個函數(顯式或隱式),你必須使用內聯。這是優化程序爲什麼忽略內聯作爲優化提示的另一個原因,只是做了它想做的事情。停止考慮內聯作爲優化;它只是繞過ODR。 –

0

編輯 @Leon(下圖)說,我的回答(轉載如下)是不正確的。正確的答案描述here - 簡而言之,如果編譯器決定不內聯函數,它仍將它放入目標模塊中。但是鏈接器會選擇不同模塊中的一個(可能是很多)副本,並丟棄所有其他模塊。


你是正確的:因爲每次編譯器決定把一個內聯函數,你不會得到「多重定義」的錯誤,這讓當前模塊中的函數static。這意味着您可以通過代碼散佈大量的大型函數副本。

+1

這是不正確的。見http://stackoverflow.com/questions/4193639/inline-function-linkage/4193698#4193698 – Leon

+0

哇。你每天學習新的東西。我知道'inline'函數在編譯成的每個模塊中 - 我沒有意識到鏈接器選擇了一個並剝離了所有其他模塊。 –

+0

在這個問題「多重定義」錯誤出現http://stackoverflow.com/questions/30803019/when-we-define-a-class-member-function-in-header-file-of-that-c​​lass-then-內聯所以我認爲職位很重要.. –

相關問題