11 前置宣告使用時機詳解

2021-10-24 05:35:17 字數 2510 閱讀 7356

這篇文章很大程度是受到exceptional c++ (hurb99)書中第四章 compiler  firewalls and the pimpl idiom  (編譯器防火牆和pimpl慣用法) 的啟發,這一章講述了減少編譯時依賴的意義和一些慣用法,其實最為常用又無任何***的是使用前置宣告來取代包括標頭檔案。

item 26 的guideline - "never #include a header when a forward declaration will suffice"

在這裡,我自己總結了可以使用前置宣告來取代包括標頭檔案的各種情況和給出一些示例**。

首先,我們為什麼要包括標頭檔案?問題的回答很簡單,通常是我們需要獲得某個型別的定義(definition)。那麼接下來的問題就是,在什麼情況下我們才需要型別的定義,在什麼情況下我們只需要宣告就足夠了?問題的回答是當我們需要知道這個型別的大小或者需要知道它的函式簽名的時候,我們就需要獲得它的定義。

假設我們有型別a和型別c,在哪些情況下在a需要c的定義:

a繼承至c

a有乙個型別為c的成員變數

a有乙個型別為c的指標的成員變數

a有乙個型別為c的引用的成員變數

a有乙個型別為std::list的成員變數

a有乙個函式,它的簽名中引數和返回值都是型別c

a有乙個函式,它的簽名中引數和返回值都是型別c,它呼叫了c的某個函式,**在標頭檔案中

a有乙個函式,它的簽名中引數和返回值都是型別c(包括型別c本身,c的引用型別和c的指標型別),並且它會呼叫另外乙個使用c的函式,**直接寫在a的標頭檔案中

c和a在同乙個名字空間裡面

c和a在不同的名字空間裡面

1,沒有任何辦法,必須要獲得c的定義,因為我們必須要知道c的成員變數,成員函式。

2,需要c的定義,因為我們要知道c的大小來確定a的大小,但是可以使用pimpl慣用法來改善這一點,詳情請

看hurb的exceptional c++。

3,4,不需要,前置宣告就可以了,其實3和4是一樣的,引用在物理上也是乙個指標,它的大小根據平台不同,可能是32位也可能是64位,反正我們不需要知道c的定義就可以確定這個成員變數的大小。

5,不需要,有可能老式的編譯器需要。標準庫裡面的容器像list, vector,map,

在包括乙個list,vector,map型別的成員變數的時候,都不需要c的定義。因為它們內部其實也是使用c的指標作為成員變數,它們的大小一開始就是固定的了,不會根據模版引數的不同而改變。

6,不需要,只要我們沒有使用到c。

7,需要,我們需要知道呼叫函式的簽名。

8,8的情況比較複雜,直接看**會比較清楚一些。

c& dotoc(c&);

c& dotoc2(c& c) ;

從上面的**來看,a的乙個成員函式dotoc2呼叫了另外乙個成員函式dotoc,但是無論是dotoc2,還是dotoc,它們的的引數和返回型別其實都是c的引用(換成指標,情況也一樣),引用的賦值跟指標的賦值都是一樣,無非就是整形的賦值,所以這裡即不需要知道c的大小也沒有呼叫c的任何函式,實際上這裡並不需要c的定義。

但是,我們隨便把其中乙個c&換成c,比如像下面的幾種示例:

1.

c& dotoc(c&);

c& dotoc2(c c) ;

2.c& dotoc(c);

c& dotoc2(c& c) ;

3.c dotoc(c&);

c& dotoc2(c& c) ;

4.c& dotoc(c&);

c dotoc2(c& c) ;

無論哪一種,其實都隱式包含了乙個拷貝建構函式的呼叫,比如1中引數c由拷貝建構函式生成,3中dotoc的返回值是乙個由拷貝建構函式生成的匿名物件。因為我們呼叫了c的拷貝建構函式,所以以上無論那種情形都需要知道c的定義。

9和10都一樣,我們都不需要知道c的定義,只是10的情況下,前置宣告的語法會稍微複雜一些。

最後給出乙個完整的例子,我們可以看到在兩個不同名字空間的型別a和c,a是如何使用前置宣告來取代直接包括c的標頭檔案的:

a.h

#pragma once

#include #include #include #include //不同名字空間的前置宣告方式

namespace test1

namespace test2

;

private:

std::list_list;

std::vector_vector;

std::map_map;

c* _pc;

c& _rc;

};}

c.h

#ifndef c_h

#define c_h

#include namespace test1

{

class c

{public:

void print() {std::cout<<"class c"<

詳解C 前置宣告

前置宣告是c c 開發中比較常用的技巧,主要用在三種情形 前置宣告作用 根據其用途,前置宣告的主要作用為 前兩種用途好理解,第三種稍微複雜點,但卻是前置宣告最重要的用途。其解決類a包含類b,同時類b包含類a的依賴問題。迴圈依賴一般是設計層面的問題,可通過介面 引入輔助類等手段化解。前置宣告也能解決,...

STL各種容器的使用時機詳解

c 標準程式庫提供了各具特長的不同容器。現在的問題是 該如何選擇最佳的容器類別?下表給出了概述。但是其中有些描述可能不一定實際。例如 如果你需呀處理的元素數量很少,可以虎落複雜度,因為線性演算法通常對元素本身的處理過程比較快,這種情況下,顯性複雜度搭配快速的元素處理 要比 對數複雜度搭配慢的元素處理...

前置宣告的使用

本貼為 這篇文章很大程度是受到exceptional c hurb99 書中第四章 compiler firewalls and the pimpl idiom 編譯器防火牆和pimpl慣用法 的啟發,這一章講述了減少編譯時依賴的意義和一些慣用法,其實最為常用又無任何 的是使用前置宣告來取代包括標頭...