[C/C++]類別互相引用(Class include each other)

最近開始久違的寫C++程式,然後因為物件上的關係,所以某個A類別會擁有B類別,同時B類別會需要知道A類別

為了能夠壤兩個類別都能夠看到,所以依照直覺的想法,會使兩方的標頭檔(Header file)都會Include彼此,但是此時編譯器卻會發生問題,究竟是為什麼呢? 這樣的想法不是很合理嗎? 



但其實編譯器在解讀時是會出現問題的,究竟哪裡有問題?

經過朋友的解說後,解決了問題也知道了原因,這邊來介紹一下給需要知道的人。

前言

 


 

最近開始久違的寫C++程式,然後因為物件上的關係,所以某個A類別會擁有B類別,同時B類別會需要知道A類別

為了能夠壤兩個類別都能夠看到,所以依照直覺的想法,會使兩方的標頭檔(Header file)都會Include彼此,但是此時編譯器卻會發生問題,究竟是為什麼呢? 這樣的想法不是很合理嗎? 

 

但其實編譯器在解讀時是會出現問題的,究竟哪裡有問題?

經過朋友的解說後,解決了問題也知道了原因,這邊來介紹一下給需要知道的人。

 

類別互相引用

 


 

有時候在開發物件導向的程式時,免不了因為一些OO關係,需要讓某個A類別會擁有B類別,同時B類別會需要知道A類別:

舉個例子好了,今天我有一個汽車的類別,汽車除了車體本身,會需要輪胎來轉動,使車子能前進;在汽車中會有一個里程錶,是用來計算輪胎走的公里數,這個時候可以寫成汽車的類別擁有輪胎來驅動輪胎前進,輪胎在轉動時會透過知道汽車,回報轉的次數給汽車。

(這邊只是舉個例子,可能有人會說車子壞掉時,輪胎可以換下來,所以車子應該不是擁有輪胎,而是知道輪胎,但這部分不是今天的主軸,OO的設計關係是看每個人的定義)

 

標頭檔互相引用的錯誤的原因

 


 

這邊我們拿A與B類別來解釋,前面提到「A類別會擁有B類別,同時B類別會需要知道A類別」,因為擁有B,所以需要include B,而B因為知道A,貌似直覺的做法B也會include A,此時在編譯的程序就會變成:

A class -> A Include B-> 進入B class -> B include A -> A class

 

所以會再次去A class的標頭檔(如下程式碼)

A.h


#ifndef A_H
#define A_H

#include "B.h"

class A
{
public:
	A(void);
	~A(void);
private:
	B b;
};

#endif

 

B.h


#ifndef B_H
#define B_H

#include "A.h"

class B
{
public:
	B(void);
	~B(void);
private:
	A *a; 
};

#endif

 

依照常理來說,一般我們在寫標頭檔時,會使用 #ifndef 、#define、#endif的前置處理指令,確保只會被編譯過一次,之後被include多次時,不會再被編譯:


#ifndef A_H
#define A_H

class A{
 //....
}

#endif

 

但是問題卻來,編譯時編譯A檔案,此發實現include B,便跳至B檔案,卻又發現B檔案有include A,再次跳回A檔案時,卻會因為A檔案先前編譯時,因為有加入#ifndef A_H與#define A_H的關係,定義過A_H,便不會再往下編譯A class,因此而又跳回B檔案,造成B檔案不認識A Class而在編譯其出錯。

 

但是,其實我們的B Class只是知道A(pointer)而已,根本不需要include A.h

 

解決方式-前置宣告(Forward Declartion)

 


 

我們可以透過前至宣告的方式來告訴編譯器「先知道這個class的存在,至於他的定義後面會說明」。

只要不涉及生成或操作的話,前至宣告可以用在指標或參考類別。

然後再.cpp檔實際操作時,在include 類別標頭檔:

 

 

A.h


#ifndef A_H
#define A_H

#include "B.h"

class A
{
public:
	A(void);
	~A(void);
private:
	B b;
};

#endif

A.cpp


#include "A.h"


A::A(void)
{
}


A::~A(void)
{
}

 

B類別稍微修改一下:

B.h


#ifndef B_H
#define B_H

class A;

class B
{
public:
	B(void);
	~B(void);
private:
	A *a; 
};

#endif

 

在cpp檔中,我們在來incldue A.h檔

B.cpp


#include "B.h"
#include "A.h"

B::B(void)
{
}


B::~B(void)
{
}

 

以上的原因與解決方式,希望可以幫助到遇到此問題的人可以解惑!

 


 

文章中的敘述如有觀念不正確錯誤的部分,歡迎告知指正 謝謝 =)

另外要轉載請附上出處 感謝