1. 程式人生 > 程式設計 >簡述C++的複雜性

簡述C++的複雜性

1. C++真的很複雜嗎

這個問題的答案是肯定的。從C++語言本身的發展和組成來看,C++語言並不是一種單一、“純粹”的程式語言,他有著複雜的內部結構。

最初,C++僅僅是在C的基礎上附加了一些object-oriented(面向物件)的特性。C++最初的名字是“C with Class”。以後C++不斷的創新和發展,融入了procedural(過程化),object-oriented(面向物件),functional(函式化),generic(泛型)以及metaprogramming(超程式設計)特性。這些能力和彈性使C++成為強大而又複雜的工具。

面對如此複雜強悍的程式語言,我們該如何理解它和學習它呢?最簡單的方法就是將C++視為一個由相關子語言組成的聯合體。在每一個特定的子語言中,它的特性趨向於直截了當,簡單易記。但當你從一個子語言跳轉到另一個子語言的時候,它的規則就會發生變化。C++的子語言有4個。

(1)C

歸根結底,C++仍然是基於C的。blocks(模組)、statements(語句、preprocessor(前處理器)、built-in data types(內建資料型別)、arrays(陣列)、pointers(指標)等,全都是來自於C。在很多方面,C++提出了比相應C版本更高階的解決問題的方法,例如行內函數、引用、函式和操作符過載等。這些特效能夠和傳統的C很好地結合在一起,可以視對C的擴充體現了C++的“A better C”的初衷。

(2)Object-Oriented C++

面向物件的C++就是C with Classes涉及到的全部:classes(類)、encapsulation(封裝)、inheritance(繼承)、polymorphism(多型)、virtual functions(虛擬函式)等。C++這一部分直接用於object-oriented design(面向物件設計)的經典規則。

(3)Template C++

這是C++ generic programming(泛型程式設計)部分,大多數程式設計師對此缺乏經驗。Template(模板)的考慮已遍及C++,而且好的程式設計規則中包含特殊的template-only(模板專用)條款已經不再不同尋常。實際上,tempalate(功能)極為強大,它提供了一種全新的programming paradigm(程式設計正規化)——template metaprogramming(TMP,模板超程式設計)。

(4)STL(Standard Template Library,標準模板庫)

STL是個template程式庫,看名稱就知道,但它是非常特殊的一個。它對容器(container)、迭代器(iterator)、演算法(algorithm)以及函式物件(function objects)的規約有極佳的緊密配合與協調。但是templates即程式庫也可以以其他的方式建立起來。STL有很多獨特的處理方法,使用STL程式設計時,需要遵循它的規則。

C++的四種子語言(sublanguages)緊密地結合在一起,但它們的確又有各自鮮明的風格。當從一種子語言轉到另一種時,為了搞笑程式設計時需要改變程式設計的策略,這是C++程式設計師可能遇到的情形,對此必須有心裡準備。例如,使用built-in(內建)型別時,pass-by-value(傳值)通常比pass-by-reference(傳引用)更高效。但當從C++的C部分轉移到Object-Oriented C++(面向物件C++),由於傳值傳值呼叫會導致建立引數的副本,呼叫使用者自定義的建構函式和解構函式會降低效率,所以更好的做法是傳const引用。在Template C++中工作時,這一點更加重要。因為在這種情況下,你甚至不知道你的操作涉及到的物件的型別。然而,當你進入STL,由於iterator(迭代器)和function objects(函式物件)以C的pointers(指標)為原型塑造出來的,所以對STL的迭代器和函式物件而言,舊式的C中的pass-by-value(傳值)規則又重新生效。

因此,C++不是使用一套規則的單一語言,而是由上面四個子語言組成的聯邦語言。每一種都有自己的規則。有了這樣的理解,就能更清楚地瞭解C++的內部結構,並能根據不同的應用需求使用不同的子語言,充分發揮C++語言的長處。

C++的的複雜性可以體現在以下三個方面:

(1)學習週期長。C++由於其內在的複雜機制,要想成為一名合格的C++程式設計師,業界的規律是3到5年。

(2)開發效率低。主要是歷史原因,C++諸多庫都停留在“很低”的層次上,使用的便利性無法與RAD工具(Rapid Application Develop,快速應用開發)相提並論。有人提議將C++庫的層次提高,但是這是一件非常苦難的工作,原因是這與C++語言的設計理念是有衝突的,C++希望最大限度地保持通用性和底層性。

(3)容易犯錯,維護難度大。C++是一種功能強大且自由度極大的語言,使用C++的過程中一不小心就犯下錯誤,留下程式碼漏洞,特別對於初學者,要能夠自如高效的使用C++語言需要很長時間的磨練。

2. C++語言複雜的原因

C++複雜的真正原因是什麼?對此,仁者見仁智者見智。因為是學院派的東西嗎?不,學院派的出來的東西就一定複雜嗎?這個理由站不住腳。

經歷三十多年的發展,C++的觸角已經遍及了當今世界學術、工業界的方方面面,體積雖然龐大,但結構卻很清晰,C++並不因此而複雜。

C++是因為支援的程式設計正規化太多了嗎?也不是,新生的語言幾乎都在走C++的成功正規化,Python和Ruby等新型動態語言的正規化甚至更多,然而它們卻以簡單和開發效率高而著稱、其實C++正真複雜的原因在於,堅守三大原則決不妥協。一是對C的完全相容,而是靜態型別檢查,三是最高效能。而其中最高效能又是這三大原則中的重點。既要發展新的特性,同時又要保持最高的效能,這是C++語言複雜性的根本原因。

C++沒有采用一些可能會降低程式效能的做法,如採用來及回收機制等。而這些做法是有可能降低C++的複雜性的。Bjarne Stroustrup教授(C++之父)在多種場合下表示,對C++的設計沒有大的後悔支出,原因在於對三大原則的堅持首先是正確的,然後,若堅守三大原則,即使重新設計一遍C++,結果也與今日相差不遠。

3.需要學習和使用C++嗎

既然C++如此複雜,那麼有必要學習和使用C++嗎?

對於這個問題,無法給出強制性的回答。在這個世界上,一定存在從來不用C++程式設計能夠出色完成特定編碼工作的程式設計師,也許他們所使用的語言就是Java、C#或者其他的程式語言。但是,我的建議是需要就用,不需要就不用學。但是,C++是一門優秀且值得學習的語言。原因是C++具有如下特性。

(1)C++是一門貫通低階到高階的語言

C++語言向下相容C語言,能夠直接通計算機的硬體和底層打交道,甚至能夠直接使用內聯彙編。向上,C++語言是4中子語言的而結合體,它所能支援的特性的豐富程度也是其他語言所難以企及的。對於一個能夠靜下心來,能夠持續持續不斷努力提升自己對計算機系統理解程度(計算機體系結構、硬體、作業系統、應用開發、軟體專案和過程管理)的程式設計師來說,C++語言是一個絕佳的選擇。

(2)C++是一種高效的語言

C++程式的執行效率與C語言相當,同時又提供了諸多的高階特性。這樣,C++語言為程式設計師創造了這樣一種可能:在利用各種高階特性(面向物件方法、泛型程式設計等)充分表達設計思想、解決各種複雜問題的同時,保持應用程式的高效執行。這也是其他程式語言難以做到的。

(3)C++是一門複雜的語言

這個觀點聽起來有些怪異。C++語言的複雜性往往是造成人們放棄C++的原因,但同時,C++語言的複雜性也有可能成為人們選擇C++語言的原因。C++的先去大師Andy Koenig在他的《C++沉思錄》裡回擊了對C++複雜的攻擊。他認為,選擇什麼樣的程式語言,取決於要解決的問題。世上沒有萬靈藥,要解決複雜的問題,必要要依賴於複雜的工具。C++程式設計師是實用主義者,他們首先保證問題能被解決,其次才能談得上其他。實際上,要解決的問題是複雜的,計算機系統使不完美的,人類的自然語言體系和表達習慣就更是不完美的。而一門成熟的通用程式語言,要在這三極之間保持平衡,談何容易。Java語言通過削減矛盾(用虛擬機器代替真實機器),削減表達能力來獲得簡單性,這也同時限制了它在實時性高計算密集的領域裡得到應用。無論是排程模擬、實時控制還是媒體編輯,一旦觸及重量型的關鍵應用,除了C++你別無選擇。C++的複雜性源於對其高效解決問題的承諾。這就好比,現實生活中,思想簡單的人不能委以重任。

(4)C++是一門成熟的程式語言。

這並不是說其他的程式語言不成熟。成熟是一種相對的概念。C++語言在其30多年的發展和使用過程中,開發了無數成功的軟體系統,積累了豐富的成功案例和可重用資源。其數量之大,應用之廣,影響之深,也是首屈一指。有興趣的讀者可以光臨Bjarne Stroustrup教授的主頁,瞭解一下C++語言在業界創造的輝煌戰績。

4.如何應對C++的複雜性

儘管C++的複雜性有其產生的深刻背景,但複雜性確實是個問題。在實踐上最突出的表現就是開發效率的降低,畢竟簡單易用的工具能帶來生產率的提高。但是C++的複雜性導致了開發效率的降低只是一種表象,它是沒有對複雜性進行有效控制而產生的後果。換句話說,問題不在於C++的複雜性,而在於使用C++的人有沒有有效控制這種複雜性。

那麼,如何應對C++的複雜性,下面給出幾點建議。

(1)用沉穩的心態去學習C++

學習程式語言,掌握語法,能上手實踐,不過是萬里長征邁出了第一步。更何況想C++這樣的語言,要做到掌握各個子語言的基本內容,都不是一件容易的事情。所以,心態一定要平穩,著急不來,更不可輕狂。要真正掌握語言,非得集中精力學習實踐一兩年,將該語言所擅長領域的應用問題熟悉過一遍,才有可能。若論精通,啊那是一個沒有止境的過程,Henry Spencer用了30年C,仍樂此不疲。Pragmatic Programmer中評價Ruby說,學上四個小時就可以用它解決實際問題,但是10年之後還為它層出不窮的心意感到驚訝。真正掌握C++語言之後,再熟悉一兩門層次不同,思維不同的語言,那就是更高層次的追求了。

要注意的是,這也是一個心理學的問題。C++語言中總是存在著一些新奇的特性,它會引起你強烈的興趣,將你的注意力從真正有用的事情中分離出來。這些被稱之為“奇技淫巧”的東西即使能短暫給你帶來自豪感,但是不應該成為你學習C++的主流。要注意,不要為了使用每一種特性而去使用,要根據實際問題和專案的需求去應用C++的特性。

(2)採用科學的學習方法

全面掌握C++固然重要,但是那不等於說,只有掌握了C++全部你愛能用來它解決問題。你可以把你對C++的理解限制於一個相對簡單的程度,只要你需要解決問題的複雜度不超過你所掌握的工具的複雜度。初學者要把C++分為邏輯層次上、難度比較獨立的部分,根據自己的需要循序漸進地的學習,利用每一部分所學解決能夠解決的問題。只有這樣,才能學得紮實。不要怕碰到問題,從某種角度來說,遇到問題是好事,因為這是彌補自己在某方面的無知的機會。自己不懂得東西太多了,只是還未暴露出來。解決了問題,你就學到了東西。

(3)正確的使用C++

C++被錯誤地使用是一種很普遍的現象,這也是C++遭受“過於複雜”的抱怨的真正原因。C++語言由4個子語言組成,C++語言提供瞭如此豐富的特性和自由度。如何選這些特性體現了C++程式設計師的真正“功力”和成熟度。

首先,要小心選擇你所使用的子語言。例如,C++是向下相容C的。那麼,是不是在任何場合下,都要使用C++的面向物件的特性呢?或者無論在什麼情況下,都選擇C,因為C更簡單?這是一刀切的思維實不可取的。顯然C有自己擅長的領域,比如裝置驅動開發、作業系統的大部分工作都不需要OOP/GP( Object Oriented Programming/Generic Programming)。然而,在更多領域,抽象與效率是並重的,這些正是C++的面向物件的特性適用的場合。

其次,充分利用現有的、經過實踐檢驗的資源。程式碼重用是現代軟體工程提倡的一種做法,不僅因為它可以提高開發效率,還因為它可以降低程式的複雜程度。如果一個高效的容器(或智慧指標)能把你從無聊的手動記憶體管理中解放出來,為啥還要用那原始的malloc/free呢?如果一個好的string類或正則表示式類能把你從繁瑣的字串處理中解脫出來,那麼為啥要手動去做這些是呢?如果一個transform(或for-each)能夠用一行程式碼把事情漂亮搞定,為啥還要手寫一個for迴圈呢?

再次,控制你程式碼的複雜程度。C++語言不是為了複雜而複雜,而是因為要解決複雜的問題而引入了複雜的機制。問題的關鍵在於,程式有時是自己把問題搞複雜了。例如在C++中,一個普通程式設計師很可能會寫出一堆高度耦合的類,很快情況就變得一團糟。但這不是C++的問題,這種情況很可能發生在任何一門面向物件語言中,因為總有程式設計師在還沒有弄懂什麼是has-a和is-a之前,就敢於在類上再寫類,就這樣一層一層的堆砌上去。它們學會了在一門特性語言中如何定義類,如何繼承類的語法,然後就認為自己已經掌握了OOP的精髓了。

由於C++是如此靈活,很多問題在C++中都有好幾中解決辦法,於是在這些選擇中進行權衡本身就成了一個困難這也是得程式設計師犯錯誤的可能性增加了。所以掌握一門優秀的設計思想(比如說優先使用組合而不是繼承),或者遵循C++社群這些年積攢下來的只會,或者說乾脆只使用C++語言中C with Class部分以規避複雜性的風險,都是程式設計師需要不斷學習和不斷實踐的。
總之,正確使用C++所應遵循的原則是:瞭解C++的高階特性,用簡單的方法解決簡單的問題,用簡單的形式解決複雜的問題,即將複雜的解決方案包裝在簡單的形式之下,重用前人的勞動成果,遵循最佳的實踐。

以上就是簡述C++的複雜性的詳細內容,更多關於C++的複雜性的資料請關注我們其它相關文章!