**對類前置宣告和包含標頭檔案的一點理解
類的前置宣告(forward declaration)和包含標頭檔案(#include)的區別常常會迷惑我們,特別是涉及兩個類相互包含的時候。因此我們有必要搞清楚二者的區別以及二者的適用場合。
首先我們需要問乙個問題是:為什麼兩個類不能互相包含標頭檔案?所謂互相包含標頭檔案,我舉乙個例子:我實現了兩個類:圖層類clayer
和符號類csymbol,它們的大致關係是圖層裡包含有符號,符號裡定義乙個相關圖層指標,具體請參考如下**(注:以下**僅供說明問題,不作為類設計參考,所以不適宜以此討論類的設計,編譯環境為microsoft visual c++ 2005,,windows xp + sp2,以下同):
// 圖層類
#pragma once
#include "symbol.h"
class clayer
;
// symbol.h
// 符號類
#pragma once
#include "layer.h"
class csymbol
;
// testunix.cpp : 定義控制台應用程式的入口點。
//
#include "stdafx.h"
#include "layer.h"
#include "symbol.h"
void main( void )
現在開始編譯,編譯出錯,出錯資訊如下:
1>正在編譯...
1>testunix.cpp
1>f:/mytest/mytest/src/testunix/symbol.h(14) : error c2143: 語法錯誤: 缺少「;」(在「*」的前面)
1>f:/mytest/mytest/src/testunix/symbol.h(14) : error c4430: 缺少型別說明符- 假定為int。注意: c++ 不支援預設int
1>f:/mytest/mytest/src/testunix/symbol.h(14) : error c4430: 缺少型別說明符- 假定為int。注意: c++ 不支援預設int
1>layer.cpp
1>f:/mytest/mytest/src/testunix/symbol.h(14) : error c2143: 語法錯誤: 缺少「;」(在「*」的前面)
1>f:/mytest/mytest/src/testunix/symbol.h(14) : error c4430: 缺少型別說明符- 假定為int。注意: c++ 不支援預設int
1>f:/mytest/mytest/src/testunix/symbol.h(14) : error c4430: 缺少型別說明符- 假定為int。注意: c++ 不支援預設int
1>symbol.cpp
1>f:/mytest/mytest/src/testunix/layer.h(18) : error c2143: 語法錯誤: 缺少「;」(在「*」的前面)
1>f:/mytest/mytest/src/testunix/layer.h(18) : error c4430: 缺少型別說明符- 假定為int。注意: c++ 不支援預設int
1>f:/mytest/mytest/src/testunix/layer.h(18) : error c4430: 缺少型別說明符- 假定為int。注意: c++ 不支援預設int
現在讓我們分析一下編譯出錯資訊(我發現分析編譯資訊對加深程式的編譯過程的理解非常有好處)。首先我們明確:編譯器在編譯檔案時,遇到#include "x.h"時,就開啟x.h檔案進行編譯,這相當於把x.h檔案的內容放在#include "x.h"處。編譯資訊告訴我們:它是先編譯testunix.cpp檔案的,那麼接著它應該編譯stdafx.h
,接著是layer.h
,如果編譯layer.h
,那麼會編譯symbol.h
,但是編譯symbol.h又應該編譯layer.h啊,這豈不是陷入乙個死迴圈? 呵呵,如果沒有預編譯指令,是會這樣的,實際上在編譯symbol.h
,再去編譯layer.h
,layer.h頭上的那個#pragma
once就會告訴編譯器:老兄,這個你已經編譯過了,就不要再浪費力氣編譯了!那麼編譯器得到這個資訊就會不再編譯layer.h而轉回到編譯symbol.h的餘下內容。當編譯到clayer *m_prellayer;這一行編譯器就會迷惑了:clayer
是什麼東西呢?我怎麼沒見過呢?那麼它就得給出一條出錯資訊,告訴你clayer沒經定義就用了呢?在testunix.cpp中#include
"layer.h"這句算是宣告編譯結束(呵呵,簡單一句彎彎繞繞不斷),下面輪到#include
"symbol.h",由於預編譯指令的阻擋,symbol.h實際上沒有得到編譯,接著再去編譯testunix.cpp的餘下內容。
當然上面僅僅是我的一些推論,還沒得到完全證實,不過我們可以稍微測試一下,假如在testunix.cpp將#include
"layer.h"和#include
"symbol.h"互換一下位置,那麼會不會先提示csymbol
類沒有定義呢?實際上是這樣的。當然這個也不能完全證實我的推論。
// 圖層類
#pragma once
//#include "symbol.h"
class csymbol;
class clayer
;
// layer.cpp
#include "stdafx.h"
#include "layer.h"
clayer::clayer(void)
clayer::~clayer(void)
} void clayer::createnewsymbol()
然後編譯,出現乙個編譯警告:>f:/mytest/mytest/src/testunix/layer.cpp(16) : warning c4150: 刪除指向不完整「csymbol」型別的指標;沒有呼叫析構函式
1> f:/mytest/mytest/src/testunix/layer.h(9) : 參見「csymbol」的宣告
看到這個警告,我想你一定悟到了什麼。下面我說說我的結論:類的前置宣告和包含標頭檔案的區別在於類的前置宣告是告訴編譯器有這種型別,但是它沒有告訴編譯器這種型別的大小、成員函式和資料成員,而包含標頭檔案則是完全告訴了編譯器這種型別到底是怎樣的(包括大小和成員)。這下我們也明白了為何前置宣告只能使用指標來進行,因為指標大小在編譯器是確定的。上面正因為前置宣告不能提供析構函式資訊,所以編譯器提醒我們:「csymbol」型別的指標是沒有呼叫析構函式。如何解決這個問題呢?在layer.cpp加上#include
"symbol.h"就可以消除這個警告。
對類前置宣告和包含標頭檔案的一點理解
類的前置宣告 forward declaration 和包含標頭檔案 include 的區別常常會迷惑我們,特別是涉及兩個類相互包含的時候。因此我們有必要搞清楚二者的區別以及二者的適用場合。首先我們需要問乙個問題是 為什麼兩個類不能互相包含標頭檔案?所謂互相包含標頭檔案,我舉乙個例子 我實現了兩個類...
類前置宣告和標頭檔案包含
類的前置宣告 forward declaration 和包含標頭檔案 include 的區別常常會迷惑我們,特別是涉及兩個類相互包含的時候。因此我們有必要搞清楚二者的區別以及二者的適用場合。首先我們需要問乙個問題是 為什麼兩個類不能互相包含標頭檔案?所謂互相包含標頭檔案,我舉乙個例子 圖層類clay...
Qt裡頭檔案包含的類的宣告
1 qt begin namespace 例如 ifndef mainwindow h define mainwindow h include qt begin namespaceclass qaction class qmenu class qtextedit qt end namespace在標...