Re: [問題] 新手關於 #include 的問題

看板C_and_CPP (C/C++)作者 (朴髮箍)時間15年前 (2011/04/08 19:39), 編輯推噓8(8015)
留言23則, 5人參與, 最新討論串2/10 (看更多)
※ 引述《kyoiku (所有狗類的主人)》之銘言: : 「要引入正確的標頭檔才能使用裡面所定義的函式」 宣告 : 例如寫上 #include <math.h> 就可以引用 math.h 裡面所有的函式。 : 可是對於剛接觸 C++ 的人來說, : 他不太清楚所寫的程式會引用到哪個標頭檔。 math 這個英文字是數學的意思, 表示在 math.h這個標頭檔裡宣告 的是有關數學運算的函式 string.h 則是字串處理的函式宣告s stdio.h 則是 standard input/output 相關的函式宣告s 所以你想要達成怎樣的功能, 就先聯想到有關的標頭檔, 再去查裡 面是否有你可以呼叫來用的函式, 通常初學也只有以下幾個標頭檔 會比較常用到: ctype.h limits.h math.h stdio.h stdlib.h string.h time.h 你要先學著大概記住他們的分類依據, 這也是為什麼檔案命名也是 非常重要的原因, 可以作有效的管理. : 所以我想說能不能把所有標頭檔在開始就都一股作氣全寫上去? : 不管要寫什麼程式,像這樣: : #include <math.h> : #include <iostream.h> : #include <iostream> : ... : ... : ... : 就先存起來複製貼上,雖然無腦但也省了找對應標頭檔的時間, : 可是看了一堆程式碼都沒看到這樣的用法? : 是高手不屑這樣用還是這樣用會出啥問題呢,@@? 先不考慮編譯的效率是怎樣, 程式碼裡的每一行指令都寓意深遠. 先來看下面的例子, 有 4個檔案分別為 first.h、second.cpp、 third.h、fourth.cpp: - // first.h struct a { int x, y; }; - // second.cpp #include "first.h" // some code here .... - // third.h #include "first.h" struct b { a qq; int t, u; }; - // fourth.cpp #include "third.h" // some code here ... 由上面的程式碼我們可以得到一個檔案的相依關係圖: ┌────┐ │ first.h│ └────┘ ↗ ↖ ┌─────┐ ┌────┐ │second.cpp│ │ third.h│ └─────┘ └────┘ ↑ ┌─────┐ │fourth.cpp│ └─────┘ 箭頭表示的關係是: 相依端 → 被相依端, 在你開始寫自己的標 頭檔後, 這樣的關係必須非常清楚. 在這樣樹狀圖中, 下面的檔案可能會呼叫上方檔案內的函式, 甚 至是使用裡面的資料結構來建立物件, 現在如果 first.h裡的結 構 a要增加一個成員 int z, 因為這樣的相依關係, 所有下游的 second.cpp、fourth.cpp很可能都要重新編譯才能因應改變, 來 做功能的更新; 但去修改結構 b卻只會影響 fourth.cpp 一個檔 案. 一個程式都是由你寫不會有什麼問題, 但是在多人分工的情況下 , 就需要良好的相依結構. 你的問題雖然是引入標準函式庫的標 頭檔(幾乎不再改變), 但還是建議你從初學就養成良好的習慣, 不然如果寫成這樣: ┌────┐ ┌────┐ │ first.h│← │ third.h│ └────┘ └────┘ ↑ ↗↖ ↑ ┌─────┐ ┌─────┐ │second.cpp│ │ fourth.h │ └─────┘ └─────┘ 哪天你不小心呼叫了不相干標頭檔裡的函式而不自知, 對方假如 對他提供的標頭檔常常作改版, 包準你重編譯到哭出來... - 另外, 附上我自己的一個心得, 在一個檔案最前面引入標頭檔, 也可以對讀者做「心理建設」, 這等於是在跟他說: 「在看這份 程式碼之前, 可能要先對以下這些標頭檔的內容有個簡單的認識 喔!」,通常對引入很多檔案的程式碼, 你讀懂他所要付出的努力 也是相對多的. -- ▂▂ ▄▂ T.T.L Listen 2 http://ppt.cc/jIUk ˇ ˇˇ ˇ 說什麼結束 ▃▃ http://ppt.cc/zQtB ψ髮箍 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 140.121.197.115

04/08 19:53, , 1F
第一個例子有點問題, 看不出來為什麼 third 要 include
04/08 19:53, 1F

04/08 19:53, , 2F
first...
04/08 19:53, 2F
程式碼已補上

04/08 19:53, , 3F
在 header 裡引用 header 應該要盡可能避免吧
04/08 19:53, 3F
利用composite來建構資料型態即有可能會發生 #if !defined(MY_STACK_H) #define MY_STACK_H #include <vector> struct MyStack { private: std::vector<int> container; // ... }; #endif

04/08 20:23, , 4F
"避免header引用header"印象中是歷史的說法 印象中現在
04/08 20:23, 4F

04/08 20:23, , 5F
提倡要讓別人include該功能header即可,因此內部應該難以
04/08 20:23, 5F

04/08 20:23, , 6F
避免再去包其他header的狀況吧
04/08 20:23, 6F

04/08 20:29, , 7F
看所謂的功能而定,標頭能少加就少加,尤其大型專案
04/08 20:29, 7F

04/08 20:44, , 8F
小弟我比較受不了的是, 在某個c.c裡, #include b.h之上
04/08 20:44, 8F

04/08 20:45, , 9F
還得自己知道要#include a.h這種情況, b需要a的話直接讓
04/08 20:45, 9F

04/08 20:46, , 10F
b.h裡 #include a.h就好了嘛Orz 只是這就撞到.h inc .h
04/08 20:46, 10F

04/08 20:46, , 11F
的情況. 目前是不太清楚這樣寫有什麼負面影響@_@"
04/08 20:46, 11F

04/08 20:57, , 12F
因為 c.c 不見得需要 a.h 的東西,如果 c.c 只用到 b.h
04/08 20:57, 12F

04/08 20:58, , 13F
的其他功能,那麼沒有道理 a.h 變動 c.c 也要跟著編吧
04/08 20:58, 13F

04/08 21:02, , 14F
而如果 b.h 確實跟 a.h 密不可分,那包一下也沒關係 LOL
04/08 21:02, 14F
補一個箭頭...

04/08 21:53, , 15F
header include header 是很正常的事
04/08 21:53, 15F

04/08 21:54, , 16F
如果要避免過複雜的 dependency 拉長編譯時間
04/08 21:54, 16F

04/08 21:54, , 17F
可以用 forward declaration + pimpl 來解決
04/08 21:54, 17F
個人覺得 forward declaration 不錯, pimpl撰寫上又多了複雜性 , 除非必要我真的會避免用它 Orz...

04/08 22:00, , 18F
V板友說的那個問題 的確應該要讓b.h去include a.h
04/08 22:00, 18F

04/08 22:00, , 19F
不然萬一b.h增加了某些功能 又包含了c.h
04/08 22:00, 19F

04/08 22:00, , 20F
那所有用到b.h的檔案都要改 會死人
04/08 22:00, 20F
※ 編輯: loveme00835 來自: 140.121.197.115 (04/08 22:02)

04/08 22:12, , 21F
樓上說的包含 c.h 問題其實是一樣的因為如果你原本就
04/08 22:12, 21F

04/08 22:13, , 22F
用不到 c.h, 那麼用到 b.h 的檔案不用修改就可以編過
04/08 22:13, 22F

04/08 22:13, , 23F
而如果你要用 c.h 的功能, 那本來就要去改動檔案了
04/08 22:13, 23F
文章代碼(AID): #1DdlFt-6 (C_and_CPP)
討論串 (同標題文章)
文章代碼(AID): #1DdlFt-6 (C_and_CPP)