類前置宣告和標頭檔案包含

2021-06-21 01:27:58 字數 2462 閱讀 5643

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

首先我們需要問乙個問題是:為什麼兩個類不能互相包含標頭檔案?所謂互相包含標頭檔案,我舉乙個例子:圖層類clayer和符號類csymbol,它們的大致關係是圖層裡包含有符號,符號裡定義乙個相關圖層指標,具體請參考如下**:

//圖層類

#pragma

once

#include 

"symbol.h

"class

clayer;//

symbol.h

//符號類

#pragma

once

#include 

"layer.h「

class

csymbol;

: 定義控制台應用程式的入口點。

#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 。。。。。。

現在讓我們分析一下編譯出錯資訊。首先我們明確:編譯器在編譯檔案時,遇到#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類沒有定義呢?實際上是這樣的。

照這樣看,兩個類的互相包含標頭檔案肯定出錯,那麼如何解決這種情況呢?一種辦法是在a類中包含b類的標頭檔案,在b類中前置盛明a類,不過注意的是b類使用a類變數必須通過指標來進行,為何前置宣告只能通過指標來使用?通過分析這個實際上我們可以得出前置宣告和包含標頭檔案的區別。我們把clayer類的**改動一下,再看下面的**: //

圖層類//

layer.h

#pragma

once

//#include "symbol.h"

class

csymbol;

class

clayer;

#include 

"stdafx.h

"#include 

"layer.h

"clayer::clayer(

void

)clayer::

~clayer(

void)}

然後編譯,出現乙個編譯警告:>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"就可以消除這個警告。 

使用前置宣告取代包含標頭檔案

c 關於宣告,定義,類的定義,標頭檔案作用,防止標頭檔案在同一編譯單元中重複引用,不具名空間 這篇文章很大程度是受到exceptional c hurb99 書中第四章 compiler firewalls and the pimpl idiom 編譯器防火牆和pimpl慣用法 的啟發,這一章講述了...

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

類的前置宣告 forward declaration 和包含標頭檔案 include 的區別常常會迷惑我們,特別是涉及兩個類相互包含的時候。因此我們有必要搞清楚二者的區別以及二者的適用場合。首先我們需要問乙個問題是 為什麼兩個類不能互相包含標頭檔案?所謂互相包含標頭檔案,我舉乙個例子 我實現了兩個類...

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

對類前置宣告和包含標頭檔案的一點理解 類的前置宣告 forward declaration 和包含標頭檔案 include 的區別常常會迷惑我們,特別是涉及兩個類相互包含的時候。因此我們有必要搞清楚二者的區別以及二者的適用場合。首先我們需要問乙個問題是 為什麼兩個類不能互相包含標頭檔案?所謂互相包含...