關於.cpp文件包含另一個.cpp文件出錯的原因以及解決辦法


     今天打開自己以前寫代碼突然覺得在main函數中如果要用的很多自己實現的函數,如果把它們都放在main.cpp文件中太臃腫了。調試起來特別不方便。能不能把這些自己實現的函數放到另外一個文件中呢?

 


     可是又不能把這些函數放在.h文件中。因為書上說.h文件中最好只放結構體、類等的申明,函數實現最好放在.cpp文件中。好吧那我就把這些函數放到一個.cpp文件中吧。所以我就新建了一個2.cpp文件把自己實現的函數都放在里面。然后把這個2.cpp文件放在和main.cpp文件的同目錄下。在main.cpp中#include"2.cpp".重新編譯運行,一切正常。看似成功了。

     關掉這個工程后,我再次打開它想修改一下那些自己的實現的函數。突然發現在VC6.0工程Sourcs File目錄下只有main.cpp沒我2.cpp,於是我點右鍵添加2.cpp文件到Siurce File目錄下。再次編譯,出錯了。出現了重定義錯誤。報錯如下:

BiTree.obj : error LNK2005: "bool __cdecl CreateBiTree(struct BiTNode * &,char *,int &)" (?CreateBiTree@@YA_NAAPAUBiTNode@@PADAAH@Z) already defined in main.obj
BiTree.obj : error LNK2005: "void __cdecl PreOrderTraverse(struct BiTNode *)" (?PreOrderTraverse@@YAXPAUBiTNode@@@Z) already defined in main.obj
BiTree.obj : error LNK2005: "void __cdecl InOrderTraverse(struct BiTNode *)" (?InOrderTraverse@@YAXPAUBiTNode@@@Z) already defined in main.obj
BiTree.obj : error LNK2005: "void __cdecl PostOrderTraverse(struct BiTNode *)" (?PostOrderTraverse@@YAXPAUBiTNode@@@Z) already defined in main.obj
BiTree.obj : error LNK2005: "void __cdecl LeverOrderTraverse(struct BiTNode *)" (?LeverOrderTraverse@@YAXPAUBiTNode@@@Z) already defined in main.obj
Debug/BiTree_2.exe : fatal error LNK1169: one or more multiply defined symbols found
執行 link.exe 時出錯.

BiTree_2.exe - 1 error(s), 0 warning(s)

      這怎么可能呢?怎么會出現重定義錯誤呢?我明明在main.cpp文件中對2.cpp中的函數只字未提。那之前沒有將2.cpp文件添加到工程目錄下就沒錯呢?

      看到這里你可能已經想到這是怎么回事了。因為在工程編譯的時候各個.cpp文件依次單獨編譯,最后才連接到一起,當在編譯main.cpp文件時,看到main.cpp文件中有#include“2.cpp”文件時就把2.cpp中的內容和main.cpp一起編譯生成main.obj文件別忘了2.cpp文件也是.cpp文件也要單獨編譯,編譯完2.cpp文件生成2.obj文件后。再將所有編譯后的.obj文件連接到一生成.exe文件。這時就會發現2.obj中的內容main.obj中也有(因為main.cpp中#include“2.cpp”)。所以會出現重復定義的錯誤。

      這時你可能又會想到把2.cpp文件改名為2.h在main.cpp文件中#include“2.h”不就行了。因為.h文件不會單獨編譯。確實是這樣。將2.cpp改為2.h后不管工程目錄中有沒有添加2.h文件都可以。可是前面說了.h文件中最好只放聲明。(不失為一個解決問題的辦法)

 

       總結一下:要想把自己實現的函數放到同一個文件中調用,如果放在.h文件中違背了.h文件最好只放聲明的原則。如果放在.cpp文件中在main.cpp中#include相應的.cpp文件則不能將這個.cpp文件添加到工程目錄下,這樣看起來又不像是一個整體(憑什么哪個.cpp文件就不能出現在工程目錄下)。


 

 那么解決的方法到底說是什么?答案是extern

        extern可以置於變量或者函數前,以表示變量或者函數的定義在別的文件中,提示變壓器遇到此變量和函數時在其他模塊中尋找其定義。另外,extern也可用來進行鏈接指定。

        關於extern更詳細的解釋請看百度百科       

         所以我們只需這樣:如果在1.cpp中要調用2.cpp中的函數,不要在1.cpp中#include“2.cpp”,只需在1.cpp中聲明一下要調用的函數,並且聲明前加關鍵字extern。例子如下

 

//2.cpp
void func1()
{//函數的實現
}
int func2()
{
//.........
}
..............
//1.cpp要調用2.cpp中的函數
#include必要的頭文件
extern void func1();
extern int func2();
int main()
{
//可以調用2.cpp中的函數func1和func2了
return 0;
}

注意要把2.CPP文件放到工程目錄下面 

 

 


免責聲明!

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



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