1. 程式人生 > >C++中關於標頭檔案的問題

C++中關於標頭檔案的問題

標頭檔案包含問題

根據編譯原理,在編譯的過程中,只是把標頭檔案中的內容進行替換,若重複包含,就會使同一段程式碼在該檔案中出現兩次或多次,引起編譯錯誤。

介紹兩種常用的方法,
其一是#ifndef:

//A為標頭檔案名,H代表這是一個頭檔案的巨集名
#ifndef A_H_
#define A_H_
//程式碼
#endif

原理:每次編譯某一段程式碼時要判定前面是否已經編譯過
優點是受C/C++支援,可移植性好;保證內容完全相同的兩個程式碼片段不會被同時包含;
缺點是如果不同程式碼片段不小心重名的話,編譯器只編譯其一;每次編譯需要判定,所以編譯大型專案時用時較長;

其二是#pragma once:

#pragma once
//程式碼

原理:編譯檔案之前確定某一檔案只能被編譯一次
優點是不必擔心名字怎麼起,不會引起重名問題;不用判定,大型專案編譯時間大大減少
缺點是不支援跨平臺;該方式是指定的同一個檔案不被編譯兩次,如果有標頭檔案拷貝的情況,也可能會被包含兩次。

然而正是由於第一種方法支援跨平臺,現在大部分人用的還是第一種。要注意,兩種方法混用更不好,使得結構紊亂。
以上兩種方法只是在寫標頭檔案時需要注意的問題,但是,只要標頭檔案這樣保證了,就不會出現標頭檔案的包含問題了嗎?當然不是。

標頭檔案相互包含問題

看下面程式碼:

//主函式
#include <iostream>

int main()
{
    std::cout << "Hello World!\n"; 
}

class A的.h檔案:

#ifndef A_H_
#define A_H_

#include "B.h"//包含類B的標頭檔案

class A
{
public:
	B * b;//建立B類指標
public:
	A();
	~A();
};
#endif

class A的.cpp檔案:

#include "A.h"

A::A()
{
}

A::~A()
{
}

class B的.h檔案:

#ifndef B_H_
#define B_H_

#include "A.h"//包含類A的標頭檔案

class B
{
public:
	A * a;//建立A類指標
public:
	B();
	~B();
};

#endif

class B的.cpp檔案:

#include "B.h"

B::B()
{
}

B::~B()
{
}

這樣寫看似沒毛病,但是編譯時產生錯誤,而錯誤的原因就是找不到對應的類。

這個問題是由類之間的相互呼叫引出的,由於編譯是自上而下有順序的,當類之間相互呼叫時,編譯的時候就可能編譯一個類時找不到另一個類,從而產生編譯錯誤。
這個問題有兩種情況,一種是在同一檔案中,另一種是在不同檔案中。而在同一檔案中的情況,新增前置宣告就行,由於不屬於標頭檔案包含問題,就不細說了。

解決該問題的關鍵就是讓編譯器編譯時能找到相應的類
解決該問題的最佳方法就是,將檔案包含都寫在.cpp檔案中,在用到某一個類之前新增類的宣告。
將以上程式碼修改為:
主函式不變

//主函式
#include <iostream>

int main()
{
    std::cout << "Hello World!\n"; 
}

class A的.h檔案(修改後):

//A.h
#ifndef A_H_
#define A_H_

class B;//由於下面要用到類B,所以這裡宣告類B
class A
{
public:
	B * b;//建立類B的指標
public:
	A();
	~A();
};
#endif

class A的.cpp檔案(修改後):

//A.cpp
#include "A.h"
#include "B.h"//由於類A中用到類B,所以包含B的標頭檔案,且放在.cpp檔案中

A::A()
{
}

A::~A()
{
}

class B的.h檔案(修改後):

#ifndef B_H_
#define B_H_

class A;//由於下面要用到類A,所以這裡宣告類A

class B
{
public:
	A * a;//建立A類指標
public:
	B();
	~B();
};

#endif

class A的.cpp檔案(修改後):

B.cpp
#include "B.h"
#include "A.h"//由於類B中用到類A,所以包含A的標頭檔案,且放在.cpp檔案中


B::B()
{
}

B::~B()
{
}

實際上,就做了兩點修改,其一就是將標頭檔案包含都放到.cpp檔案中,其二就是在類前面分別加上前置宣告。這樣的處理方式可以說是一蹴而就,媽媽再也不用擔心我標頭檔案包含的時候出錯啦。。。

也許有的人會說,這是一種程式設計習慣,標頭檔案總是要包含在.cpp檔案中的。但是,有很多人不知道這個習慣。習慣是養成的,在初學程式設計時,沒人會告訴你程式設計習慣具體應該怎麼做,這需要自己去摸索。而且你應該理解為什麼會有這種習慣,這種習慣是為了避免什麼問題。

綜上所訴,標頭檔案中一般用#ifndef保證不會被重複編譯,檔案包含要放在.cpp檔案中,並且,檔案包含的時候要思考一下,能不包含就不要包含,以提升編譯速度。

相關推薦

c中標檔案在cpp檔案中引用和.h檔案引用的思考

       我們在編寫程式中標頭檔案是經常使用的。但是標頭檔案是應該包含在.H檔案中還是在.cpp檔案中。在這個當中有什麼樣去區別呢。  假如說我們編寫了一個a.cpp  。我們將a.cpp檔案的變數和函式申明在a.h中。在a.h檔案有使用了b.中定義的型別type1資料

C\C++中標檔案string與string.h的區別

Opencv學堂 http://mp.weixin.qq.com/s?__biz=MzA4MDExMDEyMw==&mid=100000109&idx=1&sn=7540b49e869c3e27f87c84f6f3dfe9a8&chksm

使用iostream與iostream.h區別 關於C++中標檔案使用

From:http://www.lihuasoft.net/article/show.php?id=658 經常在CSDN以及其他之類的技術論壇上問關於C++ 標頭檔案的問題。提出這些問題的往往就是那些剛學C++的新手。當初我是菜鳥的時候也問過類似的問題。    

C++ 中標檔案重複定義的問題

一、同一標頭檔案中類巢狀的疑問 假設我們有兩個類A和B,分別定義在各自的標頭檔案A.h和B.h中,但是在A中要用到B,B中也要用到A,像下面的寫法是錯誤的: class B; class A { public: B b

keil中標檔案c檔案 路徑設定 問題

被標頭檔案的路徑設定困擾了很長時間,現在終於知道了! 在keil4中標頭檔案路徑設定的方法: 假設這裡有若干個檔案,分別是: main.c dong.c peng.h 其中,main.c和dong.c都依賴與peng.h。他們的內容分別如下: main.c: 絕對路徑是

C語言中標檔案與庫檔案

1、什麼是庫檔案?     庫檔案中對常用的函式、方法進行實現並打包,使用者在使用時只需要呼叫庫檔案中的函式即可,不用再次對相關函式進行實現。 2、為什麼要有標頭檔案?     標頭檔案中是對庫檔案中的函式、方法實現進行宣告,標頭檔案可以避免重定義的風險,且標頭檔案裡包含了

C語言中標檔案相互包含問題

    .h中一般放的是同名.c檔案中定義的變數、陣列、函式的宣告,需要讓.c外部使用的宣告。 1)h檔案作用  1 方便開發:包含一些檔案需要的共同的常量,結構,型別定義,函式,變數申明;  2 提供介面:對一個軟體包來說可以提供一個給外界的介面(例如: stdio

C語言中標檔案的作用

在C語言家族程式中,標頭檔案被大量使用。一般而言,每個C++/C程式通常由標頭檔案(header files)和定義檔案(definition files)組成。標頭檔案作為一種包含功能函式、資料介面宣告的載體檔案,用

C ++標檔案的十大錯誤,如何解決這些問題

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

C++標檔案algorithm的reverse函式

reverse(beg,end) reverse()會將區間[beg,end)內的元素全部逆序;  #include<stdio.h> #include<iostream> #include<algorithm> using namespac

C++標檔案用還是“” 以及 要加.h還是不加 的問題

1.C++標頭檔案用<>包含還是” “? 答:用<>包含,編譯器會先在系統目錄下搜尋; 用” ” 包含,編譯器會先在使用者目錄下搜尋。 所以,如果使用系統標準庫,要使用<>來包含標頭檔案;使用自定義標頭檔案用” “包含最好。 ** 否則有時候會找不

c/c++標檔案引用順序

 http://www.cnblogs.com/clever101/archive/2011/08/21/2147892.html     一.《Google C++ 程式設計風格指南》裡的觀點       &

Visual Studio中標檔案stdafx.h "No such file or directory"的解決辦法

1、stdafx.h並不是標準C++標頭檔案,這裡是VS預設自定義的檔案;在系統預編譯頭時會用到。一般出現 無法開啟包括檔案: “stdafx.h”: No such file or directory這樣的錯誤,可能是由於編譯器無法通過stdafx.cpp建立一個預編譯檔案,從而其他檔案沒

C++標檔案引用模板

#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<cmath&g

c/c++標檔案中#ifndef/#define/#endif的用法

想必很多人都看過“標頭檔案中用到的 #ifndef/#define/#endif 來防止該標頭檔案被重複引用”。但是是否能理解“被重複引用”是什麼意思?標頭檔案被重複引用了,會產生什麼後果?是不是所有的標頭檔案中都要加入#ifndef/#define/#endif 這些程式碼

常用C檔案 <c...>

#include <new> // for placement new. #include <cstddef> // for ptrdiff_t, size_t #include <cstdlib> // for exit()

C++ 基礎(三)C++標檔案與原始檔的使用方法 舉例

看完這篇文章,你就知道怎麼用標頭檔案和原始檔了 http://www.cnblogs.com/fenghuan/p/4794514.html 標頭檔案:常量、變數、函式、類的宣告 原始檔:變數的定義和函式的實現 步驟一、先建立標頭檔案 #ifndef CIRCLE_H #defi

C/C++標檔案彙總

C和傳統 C++ #include<assert.h>    //設定插入點 #include <ctype.h>                //字元處理     #include <errno.h>     //定義錯誤碼 #i

轉:visual studio中標檔案和庫檔案路徑設定

visual studio中標頭檔案和庫檔案路徑設定 2017年12月12日 23:06:34 Jimmy1224 閱讀數:8993 在程式開發中,很多時候需要用到別人開發的工具包,如OpenCV和itk。一般而言,在vs中,很少使用原始檔,大部分是使用對類進行宣告的標頭檔案和封裝了類的連結

[C++] 標檔案中不要用using namespace std

先總結下:   1. using namespce std;儘量不要(或者強硬一點,不許)在標頭檔案中使用。     解析: 不讓這麼用,主要原因就是防止名字重複(即自定義變數名和std中名字重複),因為標頭檔案會被很多地方使用,你不知道這個using能覆蓋多大範圍。 &