1. 程式人生 > >C++中關於類重複定義的分析和解決方法

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程式設計的程式設計愛好者能夠好好的閱讀和分析一下,親自做做實驗,有利於個人理解。