C++的標頭檔案字尾名一般用.h還是.hpp較為合適?
如果你的標頭檔案的程式碼是c相容的,換句話說在c語言下include沒有任何問題,那就用。h
反之就用。hpp。換句話說,如果標頭檔案裡有任何c++語言的部分,比如class、namespace、template等,那就應該用。hpp
以上是我的原則,僅做參考意見。
更新:實名反對說 hpp 就是宣告 + 實現的(實際上這應該說宣告 + 定義)
編譯器處理一個翻譯單元的時候根本不管在哪個檔案宣告哪個檔案定義,你只要遵循 one definition 原則就可以了。
我們如果說 hpp 是 C++ header,我們就不能限制在 hpp 中宣告和定義一定在一起,我們完全可以宣告在一個hpp,定義在 cpp
你想怎麼組織檔案就怎麼組織檔案,你可以 hpp 裡宣告然後再 include 一個 tpp/ipp 作為定義,對於模板程式碼來說這樣就做到了 宣告/實現 分離
Something.hpp
#pragma once
namespace space {
template
class Something {
public:
void some_interface();
};
} // namespace space
#include “Something。ipp”
Something.ipp
#pragma once
namespace space {
template
void Something
// the implementation
}
} // namespace space
from Why use a “tpp” file when implementing templated functions and classes defined in a header?
=================原回答分割線===================
題主不要被誤導了,請一定記住 C 不是 C++,不要把兩者的標頭檔案混合在一起
。hpp/。hh/。H/。hxx/。h++ 是 C++ 的標頭檔案, 。h 不是
當然一般來說,如果你的專案沒有混合使用 C 和 C++ 語言,那麼你使用 。h 和 。cpp 是沒有問題的。否則你需要一個 。hpp 來 wrapper C 程式碼,一般會這麼寫:
header。hpp:
#pragma once
extern
“C”
{
#include
“header。h” // 真正的 C header
}
當然現在很多 C++ 專案還是使用 。h 和 。cpp 組合, 這是有歷史原因的[1]
Since the C language sources usually have the extension “。c” and “。h”, in the beginning it was common for C++ source files to share the same extensions or use a distinct variation to clearly indicate the C++ code file。 Today this is the practice, most C++ implementation files will use the “。cpp” extension and “。h” for the declaration of header files (the last one is still shared across most assembler and C compilers)。
編譯器其實並不關心標頭檔案格式,標頭檔案可以是任何字尾,甚至沒有後綴,但是我們一般用 。h 來表示這是 C header。但是 。h 也完全可以是 C++ 程式碼, 這樣編譯器就需要從你的程式碼中推斷出這是 C++,所以我們不如顯式指定為 hpp[2]
如果你使用 vscode, 那麼 。h 也會被識別為 C header 而不是 C++ header
[1] C++ Programming/Programming Languages/C++/Code/File Organization。 (2017, October 17)。
Wikibooks, The Free Textbook Project
。 Retrieved 16:18, January 21, 2019 from
https://
en。wikibooks。org/w/inde
x。php?title=C%2B%2B_Programming/Programming_Languages/C%2B%2B/Code/File_Organization&oldid=3314841
。
[2] Wikipedia contributors。 (2019, January 15)。 Include directive。 In
Wikipedia, The Free Encyclopedia
。 Retrieved 16:27, January 21, 2019, from
https://
en。wikipedia。org/w/inde
x。php?title=Include_directive&oldid=878517965
如果混合C/C++那麼可以區分。
如果專案中只用C++,那麼沒有必要。
如果這個檔案只能由C++使用,那麼應該使用hpp,這是防止C的編譯器誤用。
Include 的檔案會直接插入,。h和。hpp字尾都不會影響編譯器編譯的,boost 中甚至有。ipp呢。
那麼如何使用呢?
。h和。cpp配合使用。
。hpp是宣告加實現。
C/C++的工程編譯其實最重要的是。c和。cpp,一般來說你gcc 命令後面都是跟著實現檔案,不用寫。h開頭的檔案的。
所以如果你有一份模組,實現在。hpp中,就可以簡單在專案裡include 一下,不需要修改編譯命令,這就非常方便使用了。
另外,c++的模板,內斂函式等,必須編譯時看到實現,而不是在連結時,導致必須實現和宣告在一起。
boost 裡,Head only使用的時候,為了不用編譯成庫,或者需要使用方增加。cpp 的連結,出現了一種新的實現檔案。ipp,它在Head only的時候會被include 在hpp的尾部。當使用庫的時候 它會被編譯連結而不用include 。
。hpp就是c++ 的Header,一個實現加宣告的檔案,一個僅僅include 就可以使用的模組。
但是!!!實際上,你怎麼用都行,編譯器不做區分。
這是給人看的,不是給編譯器看的,只有慣用風格區別,沒有統一標準
。hpp通常用於模版類這種宣告與實現共存(不得不共存)的情況,。h檔案用於配合。cpp檔案使用。就我個人而言,只要不是純模版,一律使用。h作為字尾
。h和。hpp區別
hpp,其實質就是將。cpp的實現程式碼混入。h標頭檔案當中,定義與實現都包含在同一檔案,則該類的呼叫者只需要include該hpp檔案即可,無需再將cpp加入到project中進行編譯。而實現程式碼將直接編譯到呼叫者的obj檔案中,不再生成單獨的obj,採用hpp將大幅度減少呼叫 project中的cpp檔案數與編譯次數,也不用再發布煩人的lib與dll,因此非常適合用來編寫公用的開源庫。 hpp的優點不少,但是編寫中有以下幾點要注意:
1
、是Header Plus Plus 的簡寫。
2、
與*。h類似,hpp是C++程式標頭檔案 。
3、
是
VC
L專用的標頭檔案,已預編譯。
4、
是一般模板類的標頭檔案。
5
、一般來說,*。h裡面只有宣告,沒有實現,而*。hpp裡宣告實現都有,後者可以減少。cpp的數量。
6、*.
h裡面可以有using namespace std,而*。hpp裡則無。
7、不可包含全域性物件和全域性函式。
由於hpp本質上是作為。h被呼叫者include,所以當hpp檔案中存在全域性物件或者全域性函式,而該hpp被多個呼叫者include時,將在連結時導致符號重定義錯誤。要避免這種情況,需要去除全域性物件,將全域性函式封裝為類的靜態方法。
8、類之間不可迴圈呼叫。
在。h和。cpp的場景中,當兩個類或者多個類之間有迴圈呼叫關係時,只要預先在標頭檔案做被呼叫類的宣告即可,如下:
class B;
class A{
public:
void someMethod(B b);
};
class B{
public :
void someMethod(A a);
};
在hpp場景中,由於定義與實現都已經存在於一個檔案,呼叫者必需明確知道被呼叫者的所有定義,而不能等到cpp中去編譯。因此hpp中必須整理類之間呼叫關係,不可產生迴圈呼叫。同理,對於當兩個類A和B分別定義在各自的hpp檔案中,形如以下的迴圈呼叫也將導致編譯錯誤:
//a。hpp
#include “b。hpp”
class A{
public :
void someMethod(B b);
};
//b。hpp
#include “a。hpp”
class B{
public :
void someMethod(A a);
};
9、不可使用靜態成員。
靜態成員的使用限制在於如果類含有靜態成員,則在hpp中必需加入靜態成員初始化程式碼,當該hpp被多個文件include時,將產生符號重定義錯誤。唯一的例外是const static整型成員,因為在vs2003中,該型別允許在定義時初始化,如:
class A{
public:
const static int intValue = 123;
};
由於靜態成員的使用是很常見的場景,無法強制清除,因此可以考慮以下幾種方式(以下示例均為同一類中方法)
1。類中僅有一個靜態成員時,且僅有一個呼叫者時,可以透過局域靜態變數模擬
//方法模擬獲取靜態成員
someType getMember()
{
static someTypevalue(xxx);//作用域內靜態變數
return value;
}
2。類中有多個方法需要呼叫靜態成員,而且可能存在多個靜態成員時,可以將每個靜態成員封裝一個模擬方法,供其他方法呼叫。
someType getMemberA()
{
static someTypevalue(xxx);//作用域內靜態變數
return value;
}
someType getMemberB() {
static someTypevalue(xxx);//作用域內靜態變數
return value;
}
void accessMemberA()
{
someType member = getMemberA();//獲取靜態成員
};
//獲取兩個靜態成員
void accessStaticMember()
{
someType a = getMemberA();//獲取靜態成員
someType b = getMemberB();
};
3。第二種方法對於大部分情況是通用的,但是當所需的靜態成員過多時,編寫封裝方法的工作量將非常巨大,在此種情況下,建議使用Singleton模式,將被呼叫類定義成普通類,然後使用Singleton將其變為全域性唯一的物件進行呼叫。
如原h+cpp下的定義如下:
class A{
public :
type getMember(){
return member;
}
static type member;//靜態成員
}
採用singleton方式,實現程式碼可能如下(singleton實現請自行查閱相關文件)
//實際實現類
class Aprovider{
public :
type getMember(){
return member;
}
type member;//變為普通成員
}
//提供給呼叫者的介面類
class A{
public :
type getMember(){
return Singleton
}
}
引用自:。h和。hpp區別
對於編譯器來講沒有任何區別,實際上你使用任何字尾都可以。
實踐上,建議在一個專案中使用其中一種。
如果你的程式碼會匯出C庫,建議使用。h。
我覺得和c語言的區別出來比較好。很多時候,c和C++都是混合的,但他們的用途又不太一樣。
都可以。 建議用hpp ,
跟c的區分出來。只是為了方便而已。 具體用的時候根本不存在差異