首先,讓我們來了解下c++裡函式的情況,然後再模擬到類的情況
我們在用c++寫**時(假設原始檔只有乙個main.cpp),經常會按照以下步驟寫:
先對自定義的函式進行宣告
在main函式裡呼叫第1步裡宣告好的函式
編寫函式的實際**,這一步也叫函式的定義
簡單例子如下,
#include
using namespace std;
void
func
(void);
// 函式宣告
intmain()
void
func
(void
)// 函式定義
可以看到c++允許函式的宣告和定義分開,並且只要函式宣告後就可以拿來使用,暫時不用去實現其具體定義,這其實也是可以對c/c++**進行模組化管理的基礎。
類似於函式的宣告和定義,c++裡類的宣告和定義也是可以分開的。我們可以先宣告而暫時不定義它,這種宣告就稱為類的前置宣告,forward declaration。
class screen
;
這個前置宣告在**裡引入了名字screen,並指示screen是乙個類型別。
對於類型別screen來說,在它宣告之後定義之前是乙個不完全型別,所謂不完全型別就是我們知道screen是乙個類型別,但是我們不知道它到底包含了哪些成員。
不完全型別只能在非常有限的情況下使用:
只能定義指向這種不完全型別的指標或引用
只能宣告(但是不可以定義)以不完全型別作為引數或者返回型別的函式
以下**是乙個錯誤例子,在類link_screen裡不能使用screen去建立物件,只能去定義screen類的指標或引用
class screen;
// screen的前置宣告
class link_screen
;
以下**是正確例子,
class screen;
// screen的前置宣告
class link_screen
;
主要有2點:
節約編譯時間
我們平時在寫**時會使用#include來包含其他標頭檔案,然後呼叫這個標頭檔案提供的一些類,如果該標頭檔案裡包含了很多其他沒有被使用到的類,那麼編譯時會被一起編譯,這樣就會浪費一些不必要的時間,而使用前置宣告,編譯器就只編譯我們需要用到的類,這樣就會節約一點編譯時間
處理兩個類相互依賴的問題
假設有兩個類,叫a和b,如果a裡要用到b的成員函式,b裡要用到a的成員函式,如果直接按照如下這樣寫,就會出錯,
/******* a.h *******/
#ifndef _a_h_
#define _a_h_
#include
#include
"b.h"
class a};
#endif
// _a_h_
/*******************/
/******* b.h *******/
#ifndef _b_h_
#define _b_h_
#include
#include
"a.h"
class b};
#endif
// _b_h_
/*******************/
/***** main.h ******/
#include
"a.h"
intmain
(void
)/*******************/
這樣寫會導致無限迴圈包含,a.h包含b.h,b.h裡包含a.h,a.h裡又包含b.h,…,編譯就會出錯。
改用前置宣告,就會避免這樣的問題,不過寫法有一定的限制,只能定義指標或引用,而且不能通過指標或引用來呼叫類的方法,因為此時該類型別是不完全型別,還不知道裡面定義了哪些方法。
/******* a.h *******/
#ifndef _a_h_
#define _a_h_
#include
class b;
class a};
#endif
// _a_h_
/*******************/
/******* b.h *******/
#ifndef _b_h_
#define _b_h_
#include
class a;
class b};
#endif
// _b_h_
/*******************/
/***** main.h ******/
#include
"a.h"
#include
"b.h"
intmain
(void
)/*******************/
上述寫法是a中包含b的指標,b中包含a的指標,還可以寫成a中包含b的物件,b中包含a的指標,如下,
/******* a.h *******/
#ifndef _a_h_
#define _a_h_
#include
#include
"b.h"
class a};
#endif
// _a_h_
/*******************/
/******* b.h *******/
#ifndef _b_h_
#define _b_h_
#include
class a;
class b};
#endif
// _b_h_
/*******************/
/***** main.h ******/
#include
"a.h"
#include
"b.h"
intmain
(void
)/*******************/
這裡直接引用google c++ style裡的關於前置宣告的缺點說明:
(1) 前置宣告隱藏了依賴關係,標頭檔案改動時,使用者的**會跳過必要的重新編譯過程。(2) 前置宣告可能會被庫的後續更改所破壞。前置宣告函式或模板有時會妨礙標頭檔案開發者變動其 api.例如擴大形參型別,加個自帶預設引數的模板形參等等。
(3) 前置宣告來自命名空間std:: 的 symbol 時,其行為未定義。
(4) 很難判斷什麼時候該用前置宣告,什麼時候該用 #include 。極端情況下,用前置宣告代替 includes 甚至都會暗暗地改變**的含義.
類的前置宣告既有優點又有缺點,我們使用時可以根據具體情況去選擇。這裡再引用下google c++ style裡的關於前置宣告的使用說明,
(1) 盡量避免前置宣告那些定義在其他專案中的實體.但是如果出現類的互相依賴,使用前置宣告還是乙個比較好的解決辦法,或者通過重新對類進行設計,來避免互相依賴。(2) 函式:總是使用#include.
(3) 類模板:優先使用#include.
C 類宣告 類前置宣告
參考自 關於前置型別宣告的注意點 一 class b class a class b 上述 能夠通過編譯。二 class b class a class b 上述 報錯。error list c2079 a adata uses undefined class b c2027 use of unde...
C 模板類的前置宣告
template class linkedstack template class node template class linkedstack linkedstack bool isempty const bool isfull const t top const linkedstack add...
C 類的前置宣告用法
問題 兩個類a b相互呼叫,在兩個類a和b的標頭檔案中 include 了所需的標頭檔案,編譯報錯。為什麼呢,a需要b,b需要a,形成了迴圈,違反了程式的確定性原則。原因在於 class bbb 這種方式僅僅是一種符號宣告,告訴編譯器存在bbb這個類,不會去確定bbb這個類的所佔資源 記憶體 大小和...