C++批判的批判
1,typedef不必要?
a,typedef提供了一層間接,物件導向語言中,介面掩蓋了運行時不同具體類型間的差別,而typedef掩蓋了編譯時間不同類型間的差別,卻又不喪失型別安全
b,一般語言只能返回“值”,而typedef提供了返回“類型”的能力,這是模板元編程不可或缺的機制,除非模板元編程眼下也是不必要的
2,匯入
在不同地點分別對#include,private成員放在標頭檔中,inline函數也放在標頭檔中進行了批判,實際上原因只有一個:C++不是平台,它沒有二進位標準,它編譯後成為本地代碼,喪失了一切類型資訊;只有解決了這個問題,才能解決跟分發重用匯入相關的各種問題
3,引用是多餘的?會被破壞?
a,資源釋放問題引用比指標更明確,即提供原始對象一方負責釋放資源,而一旦用指標做介面參數,就需要約定誰來釋放資源
b,Null 參考在well-formed的程式中是不存在的,因為產生它的唯一方式是提領null 指標,而提領null 指標是未定義的行為,程式很快就會出錯,而不是像被破壞的指標一樣,有些運算出錯,有些不出,有時出錯,有時不出
C99也加入了對引用的支援
4,直接重複繼承
C++缺乏Eiffel擁有的“直接重複繼承”機制,但假如有的話,語義是什麼呢?沒看過Eiffel,不懂
5,多重繼承
論述較為精闢,對多重處理的繼承是C++的軟肋,Java禁止了多重實現繼承,但提供的“單實現繼承+多介面繼承+內部類”卻又缺乏靈活性和直觀性
6,內部類破壞物件導向?破壞複用性?
有失公允,除非物件導向排斥面向介面,複用僅止原始碼複用;1,內部類提供更好的封裝性;2,內部類經過簡單封裝後可以以可執行代碼的形式提供面向介面的複用,一個例子是“List Collections.unmodifiedList(List)”,可用內部類優雅的實現(不知實際實現如何)
7,virtual/override
C++與C#的做法給了基類作者巨大的責任,而這些本應子類作者承擔;包括C++裡的虛基類,子類的變化迫使父類作出改動
8,虛擬類型
文中說C++只提供了參數化類,沒提供虛擬類型,可從所舉的虛擬類型的例子來看,似乎用前文所鄙視的typedef即可完成,不知是否如此.
9,束縛多態
在C++裡一般稱為模板參數約束,正考慮加入下版標準;但如果只是用在書中所舉例子,模板參數約束為實現某個介面,那麼用介面做為參數就可以了,為什麼還要泛型呢?泛型表達了一種Concept,泛參檢查也應該為Concept Check,而不是Type Check
10,存取控制
Eiffel對子類存取權限不加限制只能算是一個特性,未必是優點;基於對複用的兩種不同理解和側重,C++和Eiffel選擇了對待子類的兩種不同態度;對C++私人繼承批評時所舉的例子並不恰當,造成問題的根源是強制轉型,而不是私人繼承
11,展開對象
對“.”和“->”的批評太孤立了,實際上“->”是可重載的操作符,提供了一層間接,利用這層間接可以做很多事情:資源管理,以包容的方式獲得繼承的便利(自動“擁有”被包容對象的方法)等等;Eiffel提供了“展開對象”,不知具體語義如何
12,直接重複繼承
翻到這裡才看到了Eiffel中直接重複繼承的一種用處:原來是為了在子類中調用父類同名方法;隨著Precursor加入語言,這種用法也可以被拋棄了
13,抗變與協變
傳回值協變似乎沒多大問題,參數抗變似乎也沒多大問題,問題在於參數協變;Eiffel提供了Current和like來解決,C++只能期待受束泛型了
14,強制針對介面編程
作者認為父類中的public成員在子類中重定義時改為protected或private會帶來協變問題,其實只要重定義函數的語義正確,也沒什麼;而且這種變化會帶來另外一種效果:強制針對介面編程;因為此時你的客戶程式員只能通過父類來引用你的子類對象才能訪問重定義的成員
15,垃圾收集
還是那些話題,還是那些論調,還是對記憶體外的資源管理避而不談;難道不能“解構函式+棧對象+堆對象垃圾收集”?C++只不過預設缺少“堆對象垃圾收集”,智能指標還能撐一會,Java和Eiffel則缺少“棧對象+解構函式”
16,契約式設計與CORBA IDL
作者認為CORBA IDL不支援契約式設計是一個缺陷,可我從來不敢在我的DCOM,RMI,.Net Remoting組件中使用斷言,包括最初的socket server;這可是暴露在網路環境中啊,違反前置條件是要拋異常的啊;WebService稍好一點,明確定義了異常處理,有中介軟體支援