
標頭檔 (header file) 的目的在於組織程式原始碼 (source code) 檔案,類別 (class) 、函數 (function) 、常數 (constant) 或特定識別名稱的宣告 (declaration) 都放進標頭檔中,實作則放進實作的程式碼檔案裡

C++ 程式檔案的副檔名為 .cpp ,標頭檔的副檔名則是 .h 。
為什麼要這麼區分呢?因為標頭檔代表的是程式與程式間的介面 (interface) ,通常已經開發完成的程式只需要看介面就能獲悉如何使用,不需要在乎實際實作的細節,畢竟知道怎麼用就夠了,好不好用則是另外一回事囉!
就另一方面來說,這樣也比較容易維護程式碼,因為使用開發好的程式用前置處理指令 #include 進來就行了。簡單說,就是把介面跟實作分開,介面無須在每一次測試後都連同修改,有需要修正的地方只需要修正實作的部份即可。
我們以目前的 Demo 類別當例子,介紹如何切割介面與實作。首先, Demo 類別的宣告放進 class_demo4.h 內
| 001 | // Demo 類別的標頭檔 |
| 002 | // 僅有 Demo 類別的宣告 |
| 003 | class Demo { |
| 004 | // 宣告 public 的成員 |
| 005 | public: |
| 006 | Demo(); |
| 007 | Demo(int); |
| 008 | Demo(int, int); |
| 009 | void set_a(int); |
| 010 | void set_b(int); |
| 011 | int get_a(); |
| 012 | int get_b(); |
| 013 | int do_something(); |
| 014 | |
| 015 | // 宣告 private 的成員 |
| 016 | private: |
| 017 | int a; |
| 018 | int b; |
| 019 | }; |
| 020 | |
| 021 | /* 檔名: class_demo4.h |
| 022 | 作者: Kaiching Chang |
| 023 | 時間: 2014-5 */ |
實作放到相同檔名的 class_demo4.cpp 中
| 001 | // 須引進標頭檔 |
| 002 | #include "class_demo4.h" |
| 003 | |
| 004 | // 沒有參數的建構函數 |
| 005 | Demo::Demo() { |
| 006 | set_a(1); |
| 007 | set_b(1); |
| 008 | } |
| 009 | |
| 010 | // 一個參數的建構函數 |
| 011 | Demo::Demo(int n1) { |
| 012 | set_a(n1); |
| 013 | set_b(n1); |
| 014 | } |
| 015 | |
| 016 | // 兩個參數的建構函數 |
| 017 | Demo::Demo(int n1, int n2) { |
| 018 | set_a(n1); |
| 019 | set_b(n2); |
| 020 | } |
| 021 | |
| 022 | int Demo::do_something() { |
| 023 | // 改成呼叫 getter 成員函數 |
| 024 | return get_a() + get_b(); |
| 025 | } |
| 026 | |
| 027 | // setter 與 getter 成員函數 |
| 028 | void Demo::set_a(int n) { |
| 029 | a = n; |
| 030 | } |
| 031 | |
| 032 | void Demo::set_b(int n) { |
| 033 | b = n; |
| 034 | } |
| 035 | |
| 036 | int Demo::get_a() { |
| 037 | return a; |
| 038 | } |
| 039 | |
| 040 | int Demo::get_b() { |
| 041 | return b; |
| 042 | } |
| 043 | |
| 044 | /* 檔名: class_demo4.cpp |
| 045 | 作者: Kaiching Chang |
| 046 | 時間: 2014-5 */ |
注意這裡用雙引號引入 class_demo4.h ,角括弧用在標準程式庫 (standard library) ,至於自己設計的標頭檔則是用雙引號
| 001 | // 須引進標頭檔 |
| 002 | #include "class_demo4.h" |
class_demo4.cpp 中並沒有 main() ,因此我們需要另外設計一個包含 main() 的 .cpp 檔案
| 001 | #include <iostream> |
| 002 | |
| 003 | // 須引進標頭檔 |
| 004 | #include "class_demo4.h" |
| 005 | |
| 006 | using namespace std; |
| 007 | |
| 008 | int main(void) { |
| 009 | Demo t1; |
| 010 | Demo t2(11); |
| 011 | Demo t3(11, 22); |
| 012 | |
| 013 | cout << endl; |
| 014 | cout << t1.do_something() << endl; |
| 015 | cout << t2.do_something() << endl; |
| 016 | cout << t3.do_something() << endl; |
| 017 | cout << endl; |
| 018 | |
| 019 | return 0; |
| 020 | } |
| 021 | |
| 022 | /* 檔名: class_demo5.cpp |
| 023 | 作者: Kaiching Chang |
| 024 | 時間: 2014-5 */ |
classdemo5.cpp 同樣需要引入 classdemo4.h ,不然編譯器 (compiler) 會不認識 Demo 的名稱唷!
編譯時要把 classdemo4.cpp 與 classdemo5.cpp 放在一起編譯,編譯執行結果如下

C++ 的程式基本認識大抵介紹到這裡,接下來,我們要發展一個編密碼的 Encrypt 類別,藉以介紹更多利用 C++ 開發軟體的概念。
中英文術語對照
| 標頭檔 | header file |
| 原始碼 | source code |
| 類別 | class |
| 函數 | function |
| 常數 | constant |
| 宣告 | declaration |
| 介面 | interface |
| 標準程式庫 | standard library |
| 編譯器 | compiler |
重點整理
- 標頭檔用來宣告類別、函數、常數或其他識別名稱。
- C++ 程式檔案的副檔名為 .cpp ,標頭檔的副檔名則是 .h 。
- 若定義類別的程式中沒有 main() ,就需要另一個有 main() 的 .cpp 程式來執行測試。
問題與討論
- 為什麼要額外定義標頭檔?標頭檔的用途為何?
- 程式中的介面跟實作有什麼不同?為什麼要把介面跟實作分開?
- 引進標準程式庫和自行定義的標頭檔,兩者的方式有差異嗎?
練習
- 寫一個程式 exercise1301.cpp 與 exercise1301.h ,利用 exercise1201.cpp 設計的 IntegerDemo ,將介面與實作分開。
- 寫一個程式 exercise1302.cpp 與 exercise1302.h ,利用 exercise1202.cpp 計算階層值的類別,將介面與實作分開。
- 寫一個程式 exercise1303.cpp 與 exercise1303.h ,利用 exercise1203.cpp 計算費氏數列的類別,將介面與實作分開。
the end
沒有留言:
張貼留言