c++ 中類重複定義的分析與解決辦法
在C++中將類以及類中的成員函式的宣告放在.h的標頭檔案中,而將類中成員函式的定義(即實現程式碼)放在.cpp的原始檔中,這樣我們的程式設計起來更加的模組化,但是,這樣的設計也會帶來一些問題,我們分析以下的程式碼,從中找的問題,並給出問題的解決方法。首先我們在VC下新建一個工程(工程名自己隨便命名),然後在此工程下新建兩個.h的標頭檔案(檔名分別為Animal.h和 Fish.h),繼續新建三個.cpp的原始檔(檔名分別是Animal.cpp、Fish.cpp、Main.cpp),完成後分別將以下的程式碼copy到相應的檔案下。
如下圖所示:
Animal.h
-
class Animal
- {
- public :
- Animal(int height, int weight) ;
- void eat() ;
- void sleep() ;
- virtualvoid breathe() ;
- } ;
Fish.h
- #include"Animal.h"
- class Fish :public Animal
- {
- public :
- Fish() ;
- void breathe() ;
- } ;
Animal.cpp
-
#include<iostream.h>
- #include"Animal.h"
- Animal::Animal(intheight, int weight)
- {
- }
- voidAnimal::eat()
- {
- cout << "Animal eat"<< endl ;
- }
- voidAnimal::sleep()
- {
- cout << "Animal sleep"<< endl ;
- }
- void Animal::breathe()
- {
-
cout << "Animal breathe"<< endl ;
- }
Fish.cpp
- #include<iostream.h>
- #include"Fish.h"
- Fish::Fish() :Animal(300, 400)
- {}
- voidFish::breathe()
- {
- cout << "fish breathe"<< endl ;
- }
Main.cpp
- #include<iostream.h>
- #include"Animal.h"
- #include"Fish.h"
- void fun(Animal*pAn)
- {
- pAn->breathe() ;
- }
- void main()
- {
- Fish fh ;
- Animal *pAn ;
- pAn = &fh ;
- fun(pAn) ;
- }
完成後,點選編譯後,會發現VC編譯器報錯,具體如下:
大概意思就是Animal類重複定義。
我們來分析一下原始碼。
首先是執行Main.cpp原始檔中的程式碼,發現#include "Animal.h"此句程式碼,編譯器回去查詢Animal.h標頭檔案,發現Animal這個類已經定義,繼續執行,執行到#include "Fish.h"這句程式碼時,編譯器便會去查詢Fish.h標頭檔案,在Fish.h標頭檔案中,編譯器執行到#include "Animal.h"時,便又去查詢Animal.h標頭檔案中的程式碼,再次發現類Animal的定義,這樣,編譯器感覺類Animal重複定義了兩次,於是,編譯器便會報錯。
那麼,我們該怎樣去解決這種問題呢?
方法一:
既然我們已經分析了出現這種問題的原因,那麼,我們可以發現在Main.cpp檔案中,我們引用了#include "Animal.h"標頭檔案,而當我們再次去引用#include "Fish.h"標頭檔案時,發現在Fish.h檔案中也引用了#include "Animal.h"標頭檔案,既然這樣,我們何不在Main.cpp檔案中將#include "Animal.h"註釋掉,這樣就避免了重複定義的問題了,其實這樣做也是可以的,但是,我們想想,如果我們在寫一個大型的程式時,往往有幾十個甚至成百上千個的類,其中的繼承關係又是那麼的複雜的時候,我們便會很難分析到那塊可以不寫(註釋掉),所以,這種方法不適合大型程式的設計。於是,我們又想出了下面的方法:
方法二:
看如下的程式碼(保持.cpp檔案不變,我們在.h標頭檔案上解決該問題)
Animal.h
- #ifndefANIMAL_H_H
- #defineANIMAL_H_H
- class Animal
- {
- public :
- Animal(int height, int weight) ;
- void eat() ;
- void sleep() ;
- virtualvoid breathe() ;
- } ;
- #endif
Fish.h
- #include"Animal.h"
- #ifndef FISH_H_H
- #define FISH_H_H
- class Fish :public Animal
- {
- public :
- Fish() ;
- void breathe() ;
- } ;
- #endif
觀察改寫後的程式碼,發現我們在類的定義前後分別加上了#ifndef…#define…#endif語句,哪麼這條語句有什麼作用呢?還是剛才的分析過程,當編譯器去執行Main.cpp原始檔中的程式碼,發現#include "Animal.h"此句程式碼,編譯器回去查詢Animal.h標頭檔案,執行到#ifndef ANIMAL_H_H時,編譯器會做出如下的判斷,若ANIMAL_H_H沒有被定義,便定義它(#define ANIMAL_H_H被執行)繼續執行,執行到#include "Fish.h"這句程式碼時,編譯器便會去查詢Fish.h標頭檔案,在Fish.h標頭檔案中,編譯器執行到#include "Animal.h"時,便又去查詢Animal.h標頭檔案中的程式碼,與上面的一樣,編譯器會判斷ANIMAL_H_H定義了沒有,若沒有,便進行定義,反之,將跳過#ifndef…#endif間的程式碼,繼續向後執行,知道程式執行完畢。
現在再次編譯一下更改後的程式碼,發現程式並沒有報錯,執行後輸出如下:
上面的使用#ifdef…#endif解決重複定義的問題在MFC程式設計中會經常的看到,所以,希望學習MFC程式設計的程式設計愛好者能夠好好的閱讀和分析一下,親自做做實驗,有利於個人理解。