對類前置宣告和包含標頭檔案的一點理解

2021-05-09 21:04:18 字數 3040 閱讀 7368

類的前置宣告(forward declaration)和包含標頭檔案(#include)的區別常常會迷惑我們,特別是涉及兩個類相互包含的時候。因此我們有必要搞清楚二者的區別以及二者的適用場合。

首先我們需要問乙個問題是:為什麼兩個類不能互相包含標頭檔案?所謂互相包含標頭檔案,我舉乙個例子:我實現了兩個類:

圖層類clayer

和符號類csymbol

,它們的大致關係是圖層裡包含有符號,符號裡定義乙個相關圖層指標,具體請參考如下**(注:以下**僅供說明問題,不作為類設計參考,所以不適宜以此討論類的設計,編譯環境為

microsoft visual c++ 2005,

,windows xp + sp2

,以下同):

現在開始編譯,編譯出錯,出錯資訊如下:

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

類沒有定義呢?實際上是這樣的。當然這個也不能完全證實我的推論。

然後編譯,出現乙個編譯警告:

>f:/mytest/mytest/src/testunix/layer.cpp(16) : warning c4150:

刪除指向不完整「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在標...