筆記08:C++中頭文件(.h)和源文件(.cpp)的編寫

頭文件(.h):

寫類的聲明(包括類里面的成員和方法的聲明)、函數原型、#define常數等,但一般來說不寫出具體的實現。
在寫頭文件時需要注意,有兩種方式。

#ifndef SOME_UNIQUE_NAME_HERE
#define SOME_UNIQUE_NAME_HERE
 
// contents of the header
...
 
#endif // SOME_UNIQUE_NAME_HERE
#pragma once
 
// contents of the header

#ifndef的是方式是受C/C++語言標準支持。 #ifndef方式依賴于宏名不能沖突。它不光可以保證同一個文件不會被包含多次,也能保證內容完全相同的兩個文件不會被不小心同時包含。缺點是如果不同頭文件中的宏名不小心”碰撞”,可能就會導致你看到頭文件明明存在,編譯器卻硬說找不到聲明的狀況。由于編譯器每次都需要打開頭文件才能判定是否有重復定義,因此在編譯大型項目時, #ifndef會使得編譯時間相對較長,因此一些編譯器逐漸開始支持 #pragma once的方式。
#pragma once一般由編譯器提供保證:同一個文件不會被包含多次。這里所說的”同一個文件”是指物理上的一個文件,而不是指內容相同的兩個文件。無法對一個頭文件中的一段代碼作#pragma once聲明,而只能針對文件。此方式不會出現宏名碰撞引發的奇怪問題,大型項目的編譯速度也因此提供了一些。缺點是如果某個頭文件有多份拷貝,此方法不能保證它們不被重復包含。在C/C++中,#pragma once是一個非標準但是被廣泛支持的方式。

#pragma once方式產生于#ifndef之后。#ifndef方式受C/C++語言標準的支持,不受編譯器的任何限制;而#pragma once方式有些編譯器不支持(較老編譯器不支持,如GCC 3.4版本之前不支持#pragma once),兼容性不夠好。#ifndef可以針對一個文件中的部分代碼,而#pragma once只能針對整個文件。

源文件(.cpp):

源文件主要寫實現頭文件中已經聲明的那些函數的具體代碼。需要注意的是,開頭必須#include一下實現的頭文件,以及要用到的頭文件。那么當你需要用到自己寫的頭文件中的類時,只需要#include進來就行了。
下面寫一個例子(設計一個長方體類,用它能計算不同長方體的體積和表面積):
先新建一個工程
在頭文件中:

//box.h
#pragma once

class Box
{
private:
    int a;
    int b;
    int c;
public:
    int GetVolume();
    int GetArea();
    Box(int i, int j, int k);
};
//box.cpp
#include "box.h"
int Box::GetVolume()
{
    int volume = a*b*c;
    return volume;
}
int Box::GetArea()
{
    int area = (a*b + a*c + b*c) * 2;
    return area;
}
Box::Box(int i, int j, int k)
{
    a = i;
    b = j;
    c = k;
}

*在.h中聲明,在.cpp中實現。
在源文件中:

//main.cpp
#include <iostream>
#include "box.h"
using namespace std;

int main()
{
    Box a(5, 6, 7);
    cout << "GetVolume:" << a.GetVolume() << " " << "GetArea:" << a.GetArea() << endl;
    system("pause");
    return 0;
}

運行輸出:

GetVolume:210 GetArea:214
請按任意鍵繼續. . .

頭文件與實現文件的關系

(摘自DageKing

關于兩者以前的關系,要從N年以前說起了~ long long ago,once aupon a time .......

那是一個被 遺忘的年代,在編譯器只認識.c(.cpp))文件,而不知道.h是何物的年代。

那時的人們寫了很多的.c(.cpp)文件,漸漸地,人們發現在 很多.c(.cpp)文件中的聲明語句就是相同的,但他們卻不得不一個字一個字地重復地將這些內容敲入每個.c(.cpp)文件。但更為恐怖的是,當其中 一個聲明有變更時,就需要檢查所有的.c(.cpp)文件,并修改其中的聲明,啊~簡直是世界末日降臨!
終于,有人(或許是一些人)再不能忍受這 樣的折磨,他(們)將重復的部分提取出來,放在一個新文件里,然后在需要的.c(.cpp)文件中敲入#include XXXX這樣的語句。這樣即使某個聲明發生了變更,也再不需要到處尋找與修改了---世界還是那么美好!
因為這個新文件,經常被放 在.c(.cpp)文件的頭部,所以就給它起名叫做“頭文件”,擴展名是.h.
從此,編譯器(其實是預處理器)就知道世上除了.c(.cpp)文 件,還有個.h的文件,以及一個叫做#include命令。

雖然后來又發生很多的變化,但是這樣的用法一直延續至今,只是時日久遠了,人們便淡忘了當年的緣由罷了。
提到了頭文件,就說說它的作用吧~
想 到了林銳GG寫的高質量C/C++編程上頭文件的作用的簡短描述:
(1)通過頭文件來調用庫功能。在很多場合,源代碼不便(或不準)向用戶公布, 只要向用戶提供頭文件和二進制的庫即可。用戶只需要按照頭文件中的接口聲明來調用庫功能,而不必關心接口怎么實現的。編譯器會從庫中提取相應的代碼。
(2) 頭文件能加強類型安全檢查。如果某個接口被實現或被使用時,其方式與頭文件中的聲明不一致,編譯器就會指出錯誤,這一簡單的規則能大大減輕程序員調試、改 錯的負擔。

預處理是編譯器的前驅,作用是把存儲在不同文件里的程序模塊集成為一個完整的源程序.
#include本身只是一個簡單的文件包含 預處理命令,即為把include的后面文件放到這條命令這里,除此之外,沒有其它的用處(至少我也樣認為).

參考文章:
c++中頭文件與實現文件的關系
C++中頭文件(.h)和源文件(.cpp)都應該寫些什么
C/C++中#pragma once的使用

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 一 跪 十月懷胎娘遭難,一朝落地娘心寬; 赤身無有一根線,問爹問娘要吃穿; 夜夜五更難合眼,娘...
    緩步徐行靜不嘩閱讀 557評論 0 0