1. 程式人生 > >c++ 中類重複定義的分析與解決辦法

c++ 中類重複定義的分析與解決辦法

在C++中將類以及類中的成員函式的宣告放在.h的標頭檔案中,而將類中成員函式的定義(即實現程式碼)放在.cpp的原始檔中,這樣我們的程式設計起來更加的模組化,但是,這樣的設計也會帶來一些問題,我們分析以下的程式碼,從中找的問題,並給出問題的解決方法。首先我們在VC下新建一個工程(工程名自己隨便命名),然後在此工程下新建兩個.h的標頭檔案(檔名分別為Animal.h和 Fish.h),繼續新建三個.cpp的原始檔(檔名分別是Animal.cpp、Fish.cpp、Main.cpp),完成後分別將以下的程式碼copy到相應的檔案下。

如下圖所示:


Animal.h

  1. class Animal  
  2. {  
  3. public :  
  4.            Animal(int height, int weight) ;  
  5.            void eat() ;  
  6.            void sleep() ;  
  7.            virtualvoid breathe() ;  
  8. } ;  

Fish.h

  1. #include"Animal.h"
  2. class Fish :public Animal  
  3. {  
  4. public :  
  5.       Fish() ;  
  6.       void breathe() ;  
  7. } ;  

Animal.cpp

  1. #include<iostream.h>
  2. #include"Animal.h"
  3. Animal::Animal(intheight, int weight)  
  4. {  
  5. }  
  6. voidAnimal::eat()  
  7. {  
  8.       cout << "Animal eat"<< endl ;  
  9. }  
  10. voidAnimal::sleep()  
  11. {  
  12.       cout << "Animal sleep"<< endl ;  
  13. }  
  14. void Animal::breathe()  
  15. {  
  16.       cout << "Animal breathe"<< endl ;  
  17. }  

Fish.cpp

  1. #include<iostream.h>
  2. #include"Fish.h"
  3. Fish::Fish() :Animal(300, 400)  
  4. {}  
  5. voidFish::breathe()  
  6. {  
  7.       cout << "fish breathe"<< endl ;  
  8. }  

Main.cpp

  1. #include<iostream.h>
  2. #include"Animal.h"
  3. #include"Fish.h"
  4. void fun(Animal*pAn)  
  5. {  
  6.       pAn->breathe() ;  
  7. }  
  8. void main()  
  9. {  
  10.       Fish fh ;  
  11.       Animal *pAn ;  
  12.       pAn = &fh ;  
  13.       fun(pAn) ;  
  14. }  

完成後,點選編譯後,會發現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

  1. #ifndefANIMAL_H_H
  2. #defineANIMAL_H_H
  3. class Animal  
  4. {  
  5. public :  
  6.            Animal(int height, int weight) ;  
  7.            void eat() ;  
  8.            void sleep() ;  
  9.            virtualvoid breathe() ;  
  10. } ;  
  11. #endif

Fish.h

  1. #include"Animal.h"
  2. #ifndef FISH_H_H
  3. #define FISH_H_H
  4. class Fish :public Animal  
  5. {  
  6. public :  
  7.       Fish() ;  
  8.       void breathe() ;  
  9. } ;  
  10. #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程式設計的程式設計愛好者能夠好好的閱讀和分析一下,親自做做實驗,有利於個人理解。