C++ 入門指南 4.01
單元 13 - 設計專屬的標頭檔
標頭檔 (header file) 的目的在於組織程式原始碼 (source code) 檔案,類別 (class) 、函數 (function) 、常數 (constant) 或特定識別名稱的宣告 (declaration) 都放進標頭檔中,實作則放進實作的程式碼檔案裡
C++ 程式檔案的副檔名有 .cxx 、 .cc 、 .cpp 、 .c++ ,標頭檔的副檔名則是 .h 。
為什麼要這麼區分呢?因為標頭檔代表的是程式與程式間的介面 (interface) ,通常已經開發完成的程式只需要看介面就能獲悉如何使用,不需要在乎實際實作的細節,畢竟知道怎麼用就夠了,好不好用則是另外一回事囉!
就另一方面來說,這樣也比較容易維護程式碼,因為使用開發好的程式用前置處理指令 #include 進來就行了。簡單說,就是把介面跟實作分開,介面無須在每一次測試後都連同修改,有需要修正的地方只需要修正實作的部份即可。
我們以目前的 Demo 類別當例子,介紹如何切割介面與實作。首先, Demo 類別的宣告放進 class_demo4.h 內
// Demo 類別的標頭檔,僅有 Demo 類別的宣告 class Demo { // 宣告 public 的成員 public: Demo(); Demo(int); Demo(int, int); void set_a(int); void set_b(int); int get_a(); int get_b(); int do_something(); // 宣告 private 的成員 private: int a; int b; }; /* 《程式語言教學誌》的範例程式 http://kaiching.org/ 檔名:class_demo4.h 功能:示範定義標頭檔 作者:張凱慶 */
實作放到相同檔名的 class_demo4.cxx 中
// 須引進標頭檔 #include "class_demo4.h" // 沒有參數的建構函數 Demo::Demo() { set_a(1); set_b(1); } // 一個參數的建構函數 Demo::Demo(int n1) { set_a(n1); set_b(n1); } // 兩個參數的建構函數 Demo::Demo(int n1, int n2) { set_a(n1); set_b(n2); } int Demo::do_something() { // 改成呼叫 getter 成員函數 return get_a() + get_b(); } // setter 與 getter 成員函數 void Demo::set_a(int n) { a = n; } void Demo::set_b(int n) { b = n; } int Demo::get_a() { return a; } int Demo::get_b() { return b; } /* 《程式語言教學誌》的範例程式 http://kaiching.org/ 檔名:class_demo4.cxx 功能:示範定義實作檔 作者:張凱慶 */
注意這裡用雙引號引入 class_demo4.h ,角括弧用在標準程式庫 (standard library) ,至於自己設計的標頭檔則是用雙引號
// 須引進標頭檔 #include "class_demo4.h"
class_demo4.cxx 中並沒有 main() ,因此我們需要另外設計一個包含 main() 的 .cxx 檔案
#include <iostream> // 須引進標頭檔 #include "class_demo4.h" using namespace std; int main(void) { Demo t1; Demo t2(12); Demo t3(13, 24); cout << endl; cout << t1.do_something() << endl; cout << t2.do_something() << endl; cout << t3.do_something() << endl; cout << endl; return 0; } /* 《程式語言教學誌》的範例程式 https://kaiching.org/ 檔名:class_demo5.cxx 功能:示範定義實作檔 作者:張凱慶 */
classdemo5.cxx 同樣需要引入 classdemo4.h ,不然編譯器 (compiler) 會不認識 Demo 的名稱唷!
編譯時要把 classdemo4.cxx 與 classdemo5.cxx 放在一起編譯,這裡在 Windows PowerShell 使用 g++ 指令編譯,指令如下
這樣編譯出的執行檔為 class_demo5.exe ,實際在 Windows PoweShell 編譯執行結果如下圖
由於 Geany 預設只編譯執行一個程式檔案,如果需要編譯兩個以上的 C++ 程式檔案需要使用 GNU make 指令,然而 Windows 並未預設安裝 GNU make ,因此這裡直接用 Windows PoweShell 進行編譯。
如何使用 Windows PowerShell 可參考 Windows PowerShell 簡易教學。
C++ 的程式基本認識大抵介紹到這裡,接下來,我們要發展一個編密碼的 Encrypt 類別,藉以介紹更多利用 C++ 開發軟體的概念。
中英文術語對照 | |
---|---|
標頭檔 | header file |
原始碼 | source code |
類別 | class |
函數 | function |
常數 | constant |
宣告 | declaration |
介面 | interface |
標準程式庫 | standard library |
編譯器 | compiler |
重點整理 |
---|
1. 標頭檔用來宣告類別、函數、常數或其他識別名稱。 |
2. C++ 程式檔案的副檔名為 .cxx ,標頭檔的副檔名則是 .h 。 |
3. 若定義類別的程式中沒有 main() ,就需要另一個有 main() 的 .cpp 程式來執行測試。 |
問題與討論 |
---|
1. 為什麼要額外定義標頭檔?標頭檔的用途為何? |
2. 程式中的介面跟實作有什麼不同?為什麼要把介面跟實作分開? |
3. 引進標準程式庫和自行定義的標頭檔,兩者的方式有差異嗎? |
練習 |
---|
1. 寫一個程式 exercise1301.cxx 與 exercise1301.h ,利用 exercise1201.cxx 設計的 IntegerDemo ,將介面與實作分開,然後把執行部分的程式放到 exercise1301_dmeo.cxx 中。 參考程式碼 |
2. 寫一個程式 exercise1302.cxx 與 exercise1302.h ,利用 exercise1202.cxx 計算階層值的類別,將介面與實作分開,然後把執行部分的程式放到 exercise1302_dmeo.cxx 中。 參考程式碼 |
3. 寫一個程式 exercise1303.cxx 與 exercise1303.h ,利用 exercise1203.cxx 計算費氏數列的類別,將介面與實作分開,然後把執行部分的程式放到 exercise1303_dmeo.cxx 中。 參考程式碼 |
4. 寫一個程式 exercise1304.cxx 與 exercise1304.h ,利用 exercise1204.cxx 的 Point 類別,將介面與實作分開,然後把執行部分的程式放到 exercise1304_dmeo.cxx 中。 參考程式碼 |
5. 寫一個程式 exercise1305.cxx 與 exercise1305.h ,利用 exercise1205.cxx 的 Guess 類別,將介面與實作分開,然後把執行部分的程式放到 exercise1305_dmeo.cxx 中。 參考程式碼 |
6. 寫一個程式 exercise1306.cxx 與 exercise1306.h ,利用 exercise1206.cxx 的 Member 類別,將介面與實作分開,然後把執行部分的程式放到 exercise1306_dmeo.cxx 中。 參考程式碼 |
7. 寫一個程式 exercise1307.cxx 與 exercise1307.h ,利用 exercise1207.cxx 的 Text 類別,將介面與實作分開,然後把執行部分的程式放到 exercise1307_dmeo.cxx 中。 參考程式碼 |
8. 寫一個程式 exercise1308.cxx 與 exercise1308.h ,利用 exercise1208.cxx 的 Ball 類別,將介面與實作分開,注意 Point 類別的介面與實作必須放在相同資料夾下,同時在 exercise1308.h 要引入 "exercise1304.h" ,然後把執行部分的程式放到 exercise1308_demo.cxx 中,最後要留意編譯時要同時編譯 Point 類別的實作檔案。 參考程式碼 |
9. 寫一個程式 exercise1309.cxx 與 exercise1309.h ,利用 exercise1209.cxx 的 Scene 類別,將介面與實作分開,然後把執行部分的程式放到 exercise1309_dmeo.cxx 中。 參考程式碼 |
10. 寫一個程式 exercise1310.cxx 與 exercise1310.h ,利用 exercise1210.cxx 的 Game 類別,將介面與實作分開,注意 Guess 或 Ball 類別的介面與實作必須放在相同資料夾下,同時要引入 Guess 或 Ball 的標頭檔,然後把執行部分的程式放到 exercise1310_dmeo.cxx 中,編譯時要同時跟 Guess 或 Ball 的實作檔一起編譯。 參考程式碼 |
相關教學影片