我在頭文件中定義了一個類,並在同一頭文件中實現了它的功能。我沒有在函數定義中加入內聯關鍵字,因爲我認爲編譯器默認將它視爲內聯函數 - 但內聯只是編譯器的一個提示,對吧?如果編譯器由於其長度而不將其視爲內聯函數呢?我從來沒有在現實中得到錯誤信息'多重定義'。可以在頭文件中定義一個非常長的類函數成員?
struct tmp {
void print() {
...(very long)
}
};
我在頭文件中定義了一個類,並在同一頭文件中實現了它的功能。我沒有在函數定義中加入內聯關鍵字,因爲我認爲編譯器默認將它視爲內聯函數 - 但內聯只是編譯器的一個提示,對吧?如果編譯器由於其長度而不將其視爲內聯函數呢?我從來沒有在現實中得到錯誤信息'多重定義'。可以在頭文件中定義一個非常長的類函數成員?
struct tmp {
void print() {
...(very long)
}
};
我並沒有把與函數定義inline關鍵字,因爲我覺得編譯器會認爲這是一個inline函數默認
是,在類的主體定義的成員函數隱inline
。關鍵字不是必需的。
內聯只是提示編譯器吧?如果編譯器由於其長度而不將其視爲內聯函數呢?
是的,有點。實際上,inline
關鍵字有兩個含義。
第一個是你正在想的那個,它暗示了優化器在調用站點的函數體中內聯代碼。正如你所說的那樣,這只是一個提示 - 如果優化器確定這樣做會使性能更悲觀(或者由於某些其他技術原因而無法內聯),則優化器可以自由地忽略此請求。 inline關鍵字的含義可以說是過時了。現在所有的優化編譯器都忽略了inline關鍵字,因爲他們的作者認爲他們的啓發式算法比編程者更聰明。這幾乎總是如此,通過內聯標記函數來嘗試和猜測優化器是毫無意義的。
內聯關鍵字的第二個含義是放寬單定義規則(ODR),使其對鏈接器可見的同一功能有多個定義是合法的。 (儘管鏈接器在這種情況下的行爲是一個實現細節,但大多數將只是任意選擇其中一個定義。當然,如果它們完全相同,哪一個當然是行得通的。)這個inline關鍵字的含義仍然是非常重要,並解釋了爲什麼它仍然在代碼中使用。
這就是您的代碼從中受益的含義。由於在類的主體中定義的成員函數被隱式標記爲內聯,所以您不會從鏈接器中獲得多重定義的符號錯誤。
如果你在頭文件中定義的功能,但不類中的定義,換句話說,如果你做了這一點:
struct tmp {
void print();
};
void tmp::print()
{ ... }
那麼你將開始獲取多重定義的符號該頭文件包含在兩個或更多compilands中(,即,翻譯單元)。這是您需要在函數定義中添加inline
關鍵字的地方,這不是因爲您希望編譯器「內聯」它,而是因爲您希望免除ODR。
因此,對於只定義一次的小功能的'內聯'是沒有意義的? –
@lw'inline'關鍵字的兩個含義不能很容易被拉開。將函數聲明標記爲內聯是沒有意義的,除非聲明和定義是相同的,所以您不能擁有隻定義一次的內聯函數。如果你在頭文件中定義了一個函數(顯式或隱式),你必須使用內聯。這是優化程序爲什麼忽略內聯作爲優化提示的另一個原因,只是做了它想做的事情。停止考慮內聯作爲優化;它只是繞過ODR。 –
編輯 @Leon(下圖)說,我的回答(轉載如下)是不正確的。正確的答案描述here - 簡而言之,如果編譯器決定不內聯函數,它仍將它放入目標模塊中。但是鏈接器會選擇不同模塊中的一個(可能是很多)副本,並丟棄所有其他模塊。
你是正確的:因爲每次編譯器決定不把一個內聯函數,你不會得到「多重定義」的錯誤,這讓當前模塊中的函數static
。這意味着您可以通過代碼散佈大量的大型函數副本。
這是不正確的。見http://stackoverflow.com/questions/4193639/inline-function-linkage/4193698#4193698 – Leon
哇。你每天學習新的東西。我知道'inline'函數在編譯成的每個模塊中 - 我沒有意識到鏈接器選擇了一個並剝離了所有其他模塊。 –
在這個問題「多重定義」錯誤出現http://stackoverflow.com/questions/30803019/when-we-define-a-class-member-function-in-header-file-of-that-class-then-內聯所以我認爲職位很重要.. –
爲什麼?每次包含文件時,你是否真的希望編譯器能夠編譯所有代碼?什麼目的? – EJP
編譯器不會這樣做,@ejp,假設程序員足夠勝任使用包括守衛。 –
@EJP只是爲了好奇心,有時小功能變得越來越大...... –