OC 和 C++ 中聲明和實現文件分開的寫法有哪些利弊?

初學iOS開發,為什麼Android開發中所有代碼都寫在一個.java文件中,而OC中聲明和實現分別寫在.h和.m中。這兩種寫法各有什麼利弊?


題主你要注意到,所有支持import而不是#include的語言都沒有頭文件(當然反過來不是,有一些超落後的語言,都沒有頭文件了,還要使用文件路徑做import,我就不點名了)。為什麼會這樣呢?因為介面上的依賴和實現上的依賴是不一樣的。介面依賴不能循環,但是實現依賴是可以循環的。C++的h和cpp分開使得你可以做到這一點。

現在高級一點的語言,不僅沒有頭文件,而且聲明順序也是可以隨便寫的。當然了,這種編譯器需要很大的內存,因為你要分析兩遍所有的文件,第一遍產生類型資料庫,第二遍用這個資料庫來編譯所有的文件。在C/C++誕生的時候,很多機器有1M內存都已經了不起了,所以這種設計也是不可採納的。當然了,現在我們的機器都牛逼了,內存理應拿來換取我們的工作效率,所以有多少用多少。

先進的語言,也只有先進的機器才能使用。但是需求永遠是擺在第一位的。當我們的內存巨少,但是卻要支持介面不循環依賴而實現要循環依賴的時候怎麼辦?當然只能用頭文件了。


只說C++:

.h文件能當做介面API文檔,

.cpp文件被編譯成動態庫以後可以防止源代碼泄露。


補充:一,這是「源文件逐個編譯,最後鏈接 」 這一思路的產物。同時代比如Pascal雖然沒有把聲明和實現分離成兩或多個文件,但其實也是在一個文件里分成兩大塊。所以當初這一設計所要解決的需求如果還存在,那麼這個原始好處也就仍然存在:花更多時間,但可以占更低內存編譯。不過大家都知道了,這個需求雖然沒有消失,但確實越來越少了。。。(補)但是誰知道,這個本為應對低配古老機器的古老的思路在當前這個計算資源與能力基本過剩的世界,在追求編譯速度方面居然在另一個思路上意外地放異彩:為什麼昵?放在後面說。

二:單純從工作配合,特別是傾重設計和側重實現,乾脆地分成兩個文件,我認為略顯方便。

三:正如現在不管JAVA,C加加還是C#,類設計時都有人主張把對外公開的方法放代碼前頭,把一堆私有數據(通常代表內部實現的細節扔後面)。所帶來的一點小差別都許多人認同,為什麼要反對C加加天然將介面規格和內部實現分開的設計呢?現在是可以覺得它們過時了,非主流,但放當初,它確實是個看似簡單自然其實好TM天才的主意。

四:看過那些不開源的JAVA代碼嗎?為了不讓人看到實現,又懶寫文檔自認代碼即文檔的傢伙,提供一份所有方法都是空函數體的代碼。。。。好吧,其實JAVA的庫就這麼搞的。為什麼要把程序員擋在文檔閱讀這兒,我就想直接看看類定義代碼感覺更容易理解它的用法。 何苦呢?這不就是頭文件天生具備的意思?有利保護,又無礙交流。

五:方便持續集成。因為是編譯型,源代碼變成發布版的目標文件後理論上就,事實上也不可逆了,不像JAVA等語言,大量語言特徵留在目標文件里。所以明確留有介面描述文件,是你要面對一個老舊二進位系統做改進集成新功能的便利之路了。不然呢?又沒人家源代碼,又不能反彙編哪怕就編譯器能讀的出源代碼。。。怎麼改進?

六:有沒有壞處?有,用過都知道。太多問題了,但歸納就一點:把本該編譯器維護的工作,硬交給人腦來分擔了。

前面說到頭文件世界也可以編譯得很快。你不是內存大嗎?你豈止內存大,你。。。我不是說你那個很大,我是說你的計算機的那麼多核的CPU也能力過剩了。我們必須並發處理呀,哪什麼事最適合併發?互相獨立的事情最適合併發了。頭文件機制,單一文件各自編譯的設計者或許從來沒有想過哪怕個人計算機的並發資源也這麼強,但好的設計就是簡單的設計,語言不用改,編譯器不用改,你寫的代碼也不用改,直接讓並發就好。我從來就是開四個gcc進程(進程,當然)開工,成百上千個源文件滋滋叫著被編譯器輪了一遍,頭文件呢,估計上萬次被編譯器抓過來看一眼:這個沒做過,這個做過了,滾。。。

沒理由不提速呀。。。

再說了,快就好,不要太快。程序員你不在編譯時間才放鬆一下,你一直在屏幕面前使勁敲鍵盤,你和打字員有什麼區別?


C/C++/OC 的頭文件是過時的,沒啥利,歷史包袱罷了。


習慣問題。

單獨寫一個頭文件,對於使用庫的人來說,是很方便的:因為使用者可以很快速的知道這個庫有什麼可以使用的介面及定義方式。

這在一定程度上達到了文檔的效果,尤其對於一些介面很簡單的庫,其實一個頭文件外加一點注釋就搞定了。

但是對於編寫庫的人來說,就有些不方便了。

例如說如果我要修改某個函數,加一個參數。那麼我就要修改兩遍(代碼和頭文件),而且對於C++的類成員函數來說,寫法還有一點點的不同,簡單的copy paste之外還要再改改。

雖然這工作量也不算大,但是總有些時候頭昏腦脹了忘了改或者改得不同步,導致編譯錯誤或者什麼其他的bug。


優勢就是簡單粗暴,包含頭文件(或任意文件)就是要把它複製過來一併處理,多麼好理解。劣勢就是循環引用、包含次序不對等令人頭疼的問題。不過對於熟手來說這基本都不是問題,對新手來說比較頭疼。


給你一輛汽車,一般情況下你是不需要去關注發動機、變速箱、底盤細節的。

頭文件就像方向盤、離合器、剎車、油門、變速器。你只需要關注並使用它們即可。

至於其他細節,你知道他們的存在就行了,除非你想做一個汽車設計、製造、維修師。

就利弊來講,我覺得沒有弊。


頭文件這個是C的設計,後來C系的語言都繼承了這個思路,但是新一代的語言都沒有了。已經不必再仔細研究為什麼了,除非你要做開發工具。


不清楚java,雖然學過,但沒研究(逃。。

OC 里,.h是聲明文件,.m是實現文件。增加可讀性,將編譯(介面?)和實現分離


java和C++的語言邏輯是不同的,Java認為自己是純面向對象的語言,所有東西都是類;C++可以這麼理解是從C發展而來的一種全新語言,面向過程和面向對象,頭文件的存在確實有歷史的原因, 也有便利性,首先,就是實現了介面和實現的分離,比如說,你給別人提供一個庫,給了.h文件,當你的庫出現問題的時候,只需update二進位文件給對方即可,不涉及介面更改。系統修改最小。而且也是為了編譯鏈接的方便,編譯頭文件,佔好位置,再鏈接對應的二位文件即可,比如一個類的修改,只需編譯對應實現。

至於說那種過時,那種先進,不存在這個問題,只是語言內在邏輯和生存環境的問題。

至於說現在計算機資源過剩,資源是有限的,不存在過剩的問題,對你一個程序來說,計算機的資源是過剩的,計算機上不運行一個程序。


同意@陳碩

C/C++/OC 的頭文件是過時的,沒啥利,歷史包袱罷了。

另外補充一點,反對其它說.h .cpp分開,是為了.h能做介面文檔的說法。

如果僅僅為了這種需求,編譯器加個編譯選項,把語法分析之後的介面格式化並輸出不就行了?哪用得著程序員這麼費時費力的人肉寫......


oc中.h頭文件為聲明文件相當於介面 ,不過一般會把部分聲明寫在.m文件中(類擴展)防止代碼泄漏


聲明相當於介面,實現還是實現,如果人無法一下子區分兩者,如何談面向介面編程而不是實現


拿他和Java比是不科學的。

看看隔壁Pascal


其實你不覺得從某些方面來說這兩種形態根本就是同根同源的么,如果單單把oc中的.h文件拿出來那就是java中的介面,只能說兩者各有千秋吧,java文件的整合性高,而oc的.h和.m的層次感與邏輯感更強.


java流語言因為不知道有為其他語言提供介面這回事, 所以認為頭文件是無用的.

C艹流因為要照顧兒/孫/兄弟語言, 同時能提供裸動/靜態庫供兒/孫/兄弟調用. 頭文件是最簡單的方法, 可以直接以文本方式查看, 而且看不到源碼.

至於用工具或者IDE通過解析的方式提取介面的說法, 是因為這部分人沒給第三方客戶提供過庫, 不知道江湖的險惡. 介面文檔,頭文件和其他盡量能讓傻子也看懂的東西都準備好, 應對無常的客戶.


不是都說代碼首先是給人看的,然後順便才給機器運行一下嗎?

怎麼到這裡就沒人提了?

聲明相當於介面,實現還是實現,如果人無法一下子區分兩者,如何談面向介面編程而不是實現?

寫的好的C的頭文件,讓人一讀就明白介面,而不必陷入實現.同樣引導你避免取面向實現編程.

當然放在一起的語言如Java你也可以用IA,AImp之類的方法聲明和實現分開,只不過語言本身沒有這種引導,給了程序員更大的自由而已.

只要人類還認為應該面向介面編程而不是實現,這種分離的引導個人認為就是利.

當然,我也讀過很多寫的很爛的頭文件,頭文件本身和實現緊密耦合.所以說這種分離的方式只是引導,不是強制.提醒你一下,實在要破壞,也不管你. ( 好像現在的技術也做不到強制)


推薦閱讀:

現在的編譯前端技術還是用NFA和遞歸下降實現lexer和parser嗎?
有什麼可以用raspberry pi做的或者實現的有趣的/有用東西?
C#有沒有什麼比較好的入門類書籍,能夠闡明c#的思想以及基本語法,適合初學者上手?
如何從C++過渡到C#?
完成一個Scheme解釋器需要哪些知識?實現各功能都有哪些東西需要理解?

TAG:編程語言 | C | Objective-C |