C++中.cpp和.hpp的區別


原文地址:https://blog.csdn.net/qzx9059/article/details/89210571

c++中 cpp和hpp
我們可以將所有東西都放在一個.cpp文件內,編譯器會將這個.cpp編譯成.obj,即編譯單元。一個程序可以由一個編譯單元組成,也可以由多個編譯單元組成。一個.cpp對應一個.obj,然后將所有的.obj鏈接起來(通過一個叫鏈接器的程序),組成一個.exe,即程序。如果一個.cpp要用到另一個.cpp定義的函數怎么辦,只需在這個.cpp中寫上它的函數聲明。 鏈接器將所有的obj鏈接起來,但是如果碰巧有相同的函數或外部變量怎么辦?C++可以通過一種叫做鏈接屬性的關鍵字來限定,某個函數是屬於整個程序公用的,還是只在一個編譯單元obj里面使用,這些關鍵字就是extern(外部鏈接)和static(內部鏈接)。讓我們說說.h。其實沒有.h,程序也能很好的工作,但是當你發現一個外部鏈接的函數或外部變量,需要許多分聲明,因為只要使用到該函數的單元,就必須寫一份聲明在那個.cpp里面,如果要修改會很麻煩!!!.h就是為了解決這個問題而誕生的,它包含了這些公共的東西,然后所有需要使用該函數的.cpp,只需要用#include包含進去便可,以后需要修改,只是修改一份內容。#include並不是什么申請指令,只是將指定文件的內容,原封不動的拷貝進來。
不是很嚴格的講,.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}
12
//{Content of head file}   你的代碼寫在這里
#endif
這樣才能保證頭文件被多個其他文件引用(include)時,內部的數據不會被多次定義而造成錯誤。
c++中頭文件(.h)和源文件(.cpp)都應該寫些什么?
頭文件(.h):
寫類的聲明(包括類里面的成員和方法的聲明)、函數原型、#define常數等,但一般來說不寫出具體實現。
頭文件還可以定義:在編譯的時候就已知道其值的cosnt對象和inline 函數。在頭文件中定義上述實體,是因為編譯器需要它們的定義來產生代碼。
源文件(.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
12345678910111213141516
注意到開頭結尾的預編譯語句。在頭文件里,並不寫出函數的具體實現。
第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;
}
123456789101112131415161718
需要注意的是:開頭處包含了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類。
1234567891011
至此,我們工程的結構為:
注意這里聲明與定義的區別:它們最本質的區別是定義只可以出現一次,聲明可以出現多次。聲明不分配空間,而定義是要分配空間的。
————————————————
版權聲明:本文為CSDN博主「輕遠清清」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/qzx9059/article/details/89210571


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM