重復定義問題


這里說的重復定義其實包含兩個意思:

1,頭文件重復包含

2,變量或函數重復定義

對問題1,比如這樣:

有一個頭文件 c.h 。

在頭文件a.h中

#include "c.h"

在頭文件b.h中

#include "a.h"

#include "c.h"

這樣就會導致重復包含,解決辦法如下:

在c.h中

#ifndef C_H
#define C_H

//c.h中所有內容

#endinf

這樣,在第二次引用"c.h"時,由於已經定義了C_H,將不會再次引用"c.h"

當然,也要避免在頭文件里include,如果include是寫在cpp里面的話,就不會出現相互包含導致編譯出錯的問題,但是!!!!!如果頭文件里的函數寫了實現,重復包含的話仍然是要出錯的,具體看問題2的解釋

 

對於問題2:

如果在c.h中,有一個函數實現,比如:

int integer_add(const int a, const int b)
{
  return a+b;   
}

在a.cpp和b.cpp中都包含的c.h,那么編譯的時候:

a.cpp編譯得到a.obj,b.cpp編譯得到b.obj;

在鏈接時期,a.obj和b.obj和運行庫連接起來生成可執行文件的時候,就會沖突,因為兩個obj里都有一份integer_add的函數實現,導致鏈接器不知道對於調用者,應該使用哪一個副本

解決辦法:

1.使用inline修飾函數

使用inline,意味着編譯器會在調用此函數的地方把函數的目標代碼直接插入,而不是放置一個真正的函數調用,也就是說這個函數實際上已經不再存在,而是像宏一樣被就地展開了。

除了體積變大,使用inline還有這樣的問題:inline嚴格來算不是關鍵字,inline是對編譯器進行請求而不是強制,所以在一些特殊情況下,編譯器並不會真正使用inline進行修飾

類函數在類定義的時候就實現的情況下,缺省就是inline的

模板函數也是相似的

2.使用static修飾函數

使用static意味着,所有包含此頭文件的源文件中都會存在此函數的一份副本,代碼也有一定膨脹,但是相互不沖突,因為static關鍵字保證了該函數可見度為單個源文件

通過static修飾類函數,就可以使用這樣的調用方式:Integer::add(i,j);

 

對於virtual函數,它總是生成一份代碼,即使你顯式使用inline關鍵字修飾,因為:virtual函數地址會被寫到類的v-table里,在運行期才被調用。

 

對於類被多個cpp包含的情況下,沒有出現沖突,原因是遵守“單一定義規則”(One_Definition Rule, ODR) :如果對同一個類的兩個定義完全相同且出現在不同編譯單元,會被當作同一個定義

 

 相關引用:

鏈接1;

關於內聯更具體的分析

const和inline

內聯函數使用注意


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM