→ nh60211as: 那個實作在.h應該是因為template不能實作在.cpp 07/12 21:50
→ nh60211as: 不然會link time error,其他不清楚請別人回答了 07/12 21:50
→ Lipraxde: 比較細節的放 lib,其他的放 include,畢竟寫在 header 07/12 23:14
→ Lipraxde: 裡真的太方便了(x 07/12 23:14
推 Dracarys: 除了template的原因,我猜大概是為了方便inline 07/12 23:22
謝謝樓上板友們的回覆,我還真的忘了 template 的問題
→ loveme00835: 你覺得介面實作分開是為了什麼? 07/13 03:27
我個人會認為是為了好維護以及節省編譯時間,
但依稀有印象,在求學階段有聽過其中一個是安全性的原因,
不過安全性的部份我倒是不太懂...
但l大會這樣問應該是我的問題敘述不恰當,已更正了!
我想問的其實是介面與實作分開這件事該怎麼做比較適合,
比如說是什麼樣的 member function 應該在 header file 實作就好,什麼樣的
member function 又會比較適合在 .cpp 檔實作,
(例如大部分的 template 會實作在 header file)
※ 編輯: poolongkong (36.226.233.170 臺灣), 07/13/2020 03:47:24
→ loveme00835: 把東西放在標頭檔再分離編譯的情況, 對不同的 transl 07/13 03:43
→ loveme00835: ation unit 來說, 引入的多份型別/模板/物件彼此其實 07/13 03:43
→ loveme00835: 是不一樣的; 但因為要保證 ODR 所以它們被視為是相同 07/13 03:43
→ loveme00835: 的實體. 即使模板也可以細分有無特化/具現化, 一般最 07/13 03:43
→ loveme00835: 簡單的使用通常都是無特化再透過 implicit instantia 07/13 03:43
→ loveme00835: tion 來自動產生實作, 因為要完整的程式碼才有辦法做 07/13 03:43
→ loveme00835: 的這件事, 所以才會有模板實作都要寫在標頭檔的錯覺. 07/13 03:43
→ loveme00835: 事實上模板也可以寫成像你說的一樣: 介面/實作分離, 07/13 03:43
→ loveme00835: 但要很明白你的目的, 因為這種寫法很容易違反 ODR. 07/13 03:43
剛剛回覆第一則推文的時候還沒看到這些 0.0
我已經知道大部分 template 會實作在 header file 的原因 (就如同l大說的),
但除了 template 之外,
我有看過一個 class 中,部份的 member function 就實作在 header file 裡,
另一部分的實作又放在 .cpp 檔,
這種情況在實務上會有什麼特殊的意義嗎?
還是我看到的只是 coding style 不好的特例...
※ 編輯: poolongkong (36.226.233.170 臺灣), 07/13/2020 03:55:38
→ loveme00835: 先明白 include 只是複製貼上, 那再來從 ODR 的角度 07/13 03:52
→ loveme00835: 思考為什麼有的東西可以放在標頭檔裡其他的卻會造成 07/13 03:52
→ loveme00835: 連結錯誤, 再來想想這樣分開寫到底有什麼好處. 如果 07/13 03:52
→ loveme00835: 今天我分開寫沒辦法得到上述的好處, 也不會造成連結 07/13 03:52
→ loveme00835: 錯誤的話, 當然全寫在標頭檔裡比較方便囉 (節省同步 07/13 03:52
→ loveme00835: 的成本). 07/13 03:52
所以其實界面與實作分開是要根據使用情境去做一些 trade off 嗎?
(比如上面提到的 template 這樣)
※ 編輯: poolongkong (36.226.233.170 臺灣), 07/13/2020 04:01:23
→ loveme00835: 開發軟體最經常遇到的就是改變, 最害怕的也是改變. 07/13 04:02
→ loveme00835: 開發上分成兩個角色: library user & developer. use 07/13 04:02
→ loveme00835: r 因為只是不需要知道細節, 所以有一份標頭檔和已經 07/13 04:02
→ loveme00835: 編好的函式庫檔就可以做開發, developer 有任何改動, 07/13 04:02
→ loveme00835: 如果不是改在標頭檔內, 所以 user 所需要做的最多就 07/13 04:02
→ loveme00835: 是重新連結而已. 介面/實作分離一方面就是要避免 use 07/13 04:02
→ loveme00835: r 重複做編譯的動作 (編譯防火牆), 如果函式庫含有商 07/13 04:02
→ loveme00835: 業機密通常也會這樣做 (看授權) 所以撰碼的時候身分 07/13 04:02
→ loveme00835: 需要持續切換, 作為 developer 時就要思考怎樣讓 use 07/13 04:02
→ loveme00835: r 減少編譯次數, 在介面上做最少改動; 作為 user 的 07/13 04:02
→ loveme00835: 時候思考介面設計是否方便合理. 07/13 04:02
→ loveme00835: 簡單說如果一個實作萬年不變, 而且沒有需要/可能減少 07/13 04:06
→ loveme00835: 編譯次數/時間的考量, 就會直接寫在標頭檔裡. 07/13 04:06
大概明白了,感謝l大!!
之前都覺得界面與實作分開是一種絕對的關係,
所以一直以為可能有某種規則存在,
如果符合該規則就是實作在 header,不符合就實作在 .cpp 檔之類的情況,
原來跟我想的完全不一樣... Orz
※ 編輯: poolongkong (36.226.233.170 臺灣), 07/13/2020 04:12:20
→ loveme00835: 以 ISO 標準教學流程 [P1389R1] 來說這個應該歸在最 07/13 05:20
→ loveme00835: 後的工具介紹階段裡, 對語言特性更了解後才比較清楚 07/13 05:20
→ loveme00835: 該怎麼拿捏. 只是為了教學方便很容易跳過這些基礎知 07/13 05:20
→ loveme00835: 識, 不過關鍵字: ODR 可以先深入學習. 07/13 05:20
等等空閒的時間來看一下相關資料,再次感謝l大!!
※ 編輯: poolongkong (140.113.193.216 臺灣), 07/13/2020 13:26:26
推 ofd168: 每次看love大的推文都能學到很多 07/21 09:30