保證類型安全的聯結屬性(type-safe linkage)
C++ARM中解釋說type-safe linkage并不能100%的保證類型安全。既然它不那100%的保證類型安全,那么它就肯定是不安全的。統計分析顯示:即便在很苛刻的情況下,C++ 出現單獨的O-ring錯誤的可能性也只有0.3%。但我們一旦將6種這樣的可能導致出錯的情況聯合起來放在一起,出錯的幾率就變得大為可觀了。在軟件中,我們經常能夠看到一些錯誤的起因就是其怪異的聯合。OO的一個主要目的就是要減少這種奇怪的聯合出現。
大多數問題的起因都是一些難以察覺的錯誤,而不是那些簡單明了的錯誤導致問題的產生。而且在通常的情況下,不到真正的臨界時期,這樣的錯誤一般都很難被檢測到,但我們不能由此就低估了這種情況的嚴肅性。有許多的計劃都依賴于其操作的正確性,如太空計劃、財政結算等。在這些計劃中采用不安全的解決方案是一種不負責任的做法,我們應該嚴厲禁止類似情況的出現。
C++在type-safe linkage上相對于C來說有了巨大的進步。在C中,鏈接器可以將一個帶有參數的諸如f(p1,...)這樣的函數鏈接到任意的函數f()上面,而這個 f()甚至可以沒有參數或是帶有不同的參數都行。這將會導致程序在運行時出錯。由于C++的type-safe linkage機制是一種在鏈接器上實做的技巧,對于這樣的不一致性,C++將統統拒絕。
C++ARM將這樣的情況概括如下--“處理所有的不一致性->這將使得C++得以100%的保證類型安全->這將要求對鏈接器的支持或是機制(環境)能夠允許編譯器訪問在其他編譯單元里面的信息”。
那么為什么市面上的C++編譯器(至少AT&T的是如此)不提供訪問其他畢業單元中的信息的能力呢?為什么到現在也沒有一種特殊的專門為C++設計的鏈接器出現,可以100%的保證類型安全呢?答案是C++缺乏一種全局分析的能力(在上一節中我們討論過)。另外,在已有的程序組件外構造我們的系統已經是一種通用的Unix軟件開發方式,這實現了一定的重用,然而它并不能為面向對象方式的重用提供真正的彈性及一致性。
在將來, Unix可能會被面向對象的操作系統給替代,這樣的操作系統足夠的“開放”并且能夠被合適地裁剪用以符合我們的需求。通過使用管道(pipe)及標志 (flag),Unix下的軟件組件可以被重復利用以提供所需的近似功能。這種方法在一定的情況下行之有效,并且頗負效率(如小型的內部應用,或是用以進行快速原型研究),但對于大規模、昂貴的、或是對于安全性要求很高的應用來說,采取這樣的開發方法就不再適合了。在過去的十年中,集成的軟件(即不采用外部組件開發的軟件)的優點已經得到了認同。傳統的Unix系統不能提供這樣的優點。相比而言,集成的系統更加的復雜,對于開發它們的開發人員有著更多的要求,但是最終用戶(end user)要求的就是這樣的軟件。將所有的東西拙劣的放置于一起構成的系統是不可接受的?,F在,軟件開發的重心已經轉到組件式軟件開發上面來了,如公共領域的OpenDoc或是Microsoft的OLE。
對于鏈接來說,更進一步的問題出現在:不同的編譯單元和鏈接系統可能會使用不同的名字編碼方式。這個問題和type-safe linkage有關,不過我們將會在“重用性及兼容性”這節講述之。
Java使用了一種不同的動態鏈接機制,這種機制被設計的很好,沒有使用到Unix的鏈接器。Eiffel則不依賴于Unix或是其他平臺上的鏈接器來檢測這些問題,一切都由編譯器完成。
Eiffel 定義了一種系統層上的有效性(system-level validity)。一個Eiffel編譯器也就因此需要進行封閉環境下的分析,而不是依賴于鏈接器上的技巧。你也可以就此認為Eiffel程序能夠保證 100%的類型安全。對于Eiffel來說有一個缺點就是,編譯器需要干的事情太多了。(通常我們會說的是它太“慢”了,但這不夠精確)目前我們可以通過對于Eiffel提供一定的擴展來解決這個問題,如融冰技術(melting-ice technology),它可以使得我們對于系統的改動和測試可以在不需要每次都進行重新編譯的情況下進行。
現在讓我們來概括一下前兩個小節 - 有兩個原因使我們需要進行全局(或封閉環境下的)分析:一致性檢測及優化。這樣做可以減掉程序員身上大量的負擔,而缺乏它是C++中的一個很大的不足。