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() ; virtual void 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() ;
virtual void 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時,編譯器會做出如下的判斷,若FISH_H_H沒有被定義,便定義它(#define FISH_H_H被執行)繼續執行,執行到#include "Fish.h"這句程式碼時,編譯器便會去查詢Fish.h標頭檔案,在Fish.h標頭檔案中,編譯器執行到#include "Animal.h"時,便又去查詢Animal.h標頭檔案中的程式碼,與上面的一樣,編譯器會判斷FISH_H_H定義了沒有,若沒有,便進行定義,反之,將跳過#ifndef…#endif間的程式碼,繼續向後執行,知道程式執行完畢。
現在再次編譯一下更改後的程式碼,發現程式並沒有報錯,執行後輸出如下:
上面的使用#ifdef…#endif解決重複定義的問題在MFC程式設計中會經常的看到,所以,希望學習MFC程式設計的程式設計愛好者能夠好好的閱讀和分析一下,親自做做實驗,有利於個人理解。