c++ cpp和hpp的關系
首先,我們可以將所有東西都放在一個.cpp文件內,編譯器會將這個.cpp編譯成.obj,即編譯單元。一個程序可以由一個編譯單元組成,也可以由多個編譯單元組成。一個.cpp對應一個.obj,然後將所有的.obj鏈接起來(通過一個叫鏈接器的程序),組成一個.exe,即程序。如果一個.cpp要用到另一個.cpp定義的函數怎麽辦,只需在這個.cpp中寫上它的函數聲明。 鏈接器將所有的obj鏈接起來,但是如果碰巧有相同的函數或外部變量怎麽辦?C++可以通過一種叫做鏈接屬性的關鍵字來限定,某個函數是屬於整個程序公用的,還是只在一個編譯單元obj裏面使用,這些關鍵字就是extern(外部鏈接)和static(內部鏈接)。
不是很嚴格的講,*.h文件做的是類的聲明,包括類成員的定義和函數的聲明,而*.cpp文件做的類成員函數的具體實現(定義)。一個*.h文件和*.cpp文件一般是配對的。在*.cpp文件的第一行一般也是#include"*.h"文件,其實也相當於把*.h文件裏的東西復制到*.cpp文件的開頭。所以,你全部寫在*.cpp文件其實也是一樣的。
既然可以直接寫cpp,為什麽還要寫hpp?除了編程規範外,還涉及到類一個重要性質,就是封裝性。比如現在我們公司和另一家軟件公司合作,這樣就必然要互相提供一些軟件的信息(比如一些類,它到底是要做什麽的),可是在提供這些信息的同時我們又不像讓對方知道我們這些類的具體實現,畢竟這些是我們公司的算法核心和心血啊。所以這個時候就可以把類的接口(這個類是要做什麽的)放在*.h文件中,而具體類的實現放在 *.cpp文件。這時候我們只要給對方公司*.h文件就行了。這樣既提供了必要的信息,又保護了我們的核心代碼。
1.最表面的機制是:頭文件是程序的界面(是代碼界面),提供給程序員以 類、模版、函數等一系列的聲明,讓程序員知道應該怎麽調用裏面的“東西”。
2.從動態鏈接庫的角度看:頭文件提供界面,使得程序員在需要加載一個庫函數的時候(這裏也僅僅是舉簡單的例子)查看頭文件就知道怎麽加載這個動態庫內部的函數。
3.從軟件的擴展來說:將頭文件作為界面,再去定義它的實現,這樣只要保證界面不變(頭文件不變),就可以只修改實現文件,而不必修改其他的實現代碼。比如你有一個sort()函數來排序,在一個大程序中,你後來發現這個sort()有更好的算法,於是你只需要去修改函數的實現(修改.cpp文件的sort()函數的代碼),其他使用這個函數的地方可以完全保持不變,這是分割技術的第一個好處
4.從編譯的角度看:
所有源文件都是被編譯器分別劃分單元來分別編譯,在編譯的過程中,頭文件被嵌入到實現文件裏面一起作為一個編譯單元被編譯(實現文件filename.cpp裏的#include "filename.h"這一行被替換成filename.h裏面的所有內容(實際上會把預處理指令去掉,這才是預處理最本質的作用))。
舉一個簡單的例子,你定義了sort()函數,在test.h頭文件裏聲明,在test.cpp裏定義,這個時候在test.cpp裏面#include "test.h",並定義sort()函數。
你需要在頭文件內部寫預處理代碼
頭文件的所有內容,都必須包含在
#ifndef {Filename}#define {Filename}
//{Content of head file} 你的代碼寫在這裏
#endif
這樣才能保證頭文件被多個其他文件引用(include)時,內部的數據不會被多次定義而造成錯誤。
下圖是blob.hpp裏的前兩行可以看到
最後一行:
c++中頭文件(.h)和源文件(.cpp)都應該寫些什麽?
頭文件(.h):
寫類的聲明(包括類裏面的成員和方法的聲明)、函數原型、#define常數等,但一般來說不寫出具體實現
源文件(.cpp):
源文件主要寫實現頭文件中已經聲明的那些函數的具體代碼。需要註意的是,開頭必須#include一下實現的頭文件,以及要用到的頭文件。那麽當你需要用到自己寫的頭文件中的類時,只需要#include進來就行了。
下面舉個最簡單的例子來描述一下,咱就求個圓面積。
第1步,建立一個空工程(以在VS2003環境下為例)。
第2步,在頭文件的文件夾裏新建一個名為Circle.h的頭文件,它的內容如下:
#ifndef CIRCLE_H
#define CIRCLE_H
class Circle
{
private:
double r;//半徑
public:
Circle();//構造函數
Circle(double R);//構造函數
double Area();//求面積函數
};
#endif
註意到開頭結尾的預編譯語句。在頭文件裏,並不寫出函數的具體實現。
第3步,要給出Circle類的具體實現,因此,在源文件夾裏新建一個Circle.cpp的文件,它的內容如下:
#include "Circle.h"
Circle::Circle()
{
this->r=5.0;
}
Circle::Circle(double R)
{
this->r=R;
}
double Circle:: Area()
{
return 3.14*r*r;
}
需要註意的是:開頭處包含了Circle.h,事實上,只要此cpp文件用到的文件,都要包含進來!這個文件的名字其實不一定要叫Circle.cpp,但非常建議cpp文件與頭文件相對應。
最後,我們建一個main.cpp來測試我們寫的Circle類,它的內容如下:
#include <iostream>
#include "Circle.h"
using namespace std;
int main()
{
Circle c(3);
cout<<"Area="<<c.Area()<<endl;
return 1;
}
註意到開頭時有#include "Circle.h"的聲明,證明我們使用到了我們剛才寫的Circle類。
至此,我們工程的結構為:
運行一下,輸出結果為:
註意這裏聲明與定義的區別:它們最本質的區別是定義只可以出現一次,聲明可以出現多次。聲明不分配空間,而定義是要分配空間的。
http://blog.csdn.net/praker/article/details/38231757
https://www.cnblogs.com/fenghuan/p/4794514.html
c++ cpp和hpp的關系