提高對C 的認識

2021-07-28 08:05:10 字數 3947 閱讀 2033

c++中有很多 「東西」:c,過載,物件導向,模板,例外,名字空間。這麼多東西,有時讓人感到不知所措。怎麼弄懂所有這些東西呢?

c++之所以發展到現在這個樣子,在於它有自己的設計目標。理解了這些設計目標,就不難弄懂所有這些東西了。c++最首要的目標在於:

· 和c的相容性。很多很多c還存在,很多很多c程式設計師還存在。c++利用了這一基礎,並建立在 —- 我是指 「平衡在」 —- 這一基礎之上。

· 效率。作為c++的設計者和第乙個實現者,bjarne stroustrup從一開始就清楚地知道,要想把c程式設計師爭取過來,就要避免轉換語言會帶來效能上的損失,否則他們不會對c++再看第二眼。結果,他確信c++在效率上可以和c匹敵 —- 二者相差大約在5%之內。

· 和傳統開發工具及環境的相容性。各色不同的開發環境到處都是,編譯器、鏈結器和編輯器則無處不在。從小型到大型的所有開發環境,c++都要輕鬆應對,所以帶的包袱越輕越好。想移植c++?你實際上移植的只是一種語言,並利用了目標平台上現有的工具。(然而,往往也可能帶來更好的實現,例如,如果鏈結器能被修改,使得它可以處理內聯和模板在某些方面更高的要求)

· 解決真實問題的可應用性。c++沒有被設計為一種完美的,純粹的語言,不適於用它來教學生如何程式設計。它是設計為專業程式設計師的強大工具,用它來解決各種領域中的真實問題。真實世界都有些磕磕碰碰,因此,程式設計師們所依賴的工具如果偶爾出點問題,也不值得大驚小怪。

以上目標闡明了c++語言中大量的實現細節,如果沒有它們作指導,就會有摩擦和困惑。為什麼隱式生成的拷貝建構函式和賦值運算子要象現在這樣工作呢,尤其是指標(參見條款11和45)?因為這是c對struct進行拷貝和賦值的方式,和c相容很重要。為什麼析構函式不自動被宣告為virtual(參見條款14),為什麼實現細節必須出現在類的定義中(參見條款34)呢?因為不這樣做就會帶來效能上的損失,效率很重要。為什麼c++不能檢測非區域性靜態物件之間的初始化依賴關係(參見條款47)呢?因為c++支援單獨編譯(即,分開編譯源模組,然後將多個目標檔案鏈結起來,形成可執行程式),依賴現有的鏈結器,不和程式資料庫打交道。所以,c++編譯器幾乎不可能知道整個程式的一切情況。最後一點,為什麼c++不讓程式設計師從一些繁雜事務如記憶體管理(參見條款5-10)和低階指標操作中解脫出來呢?因為一些程式設計師需要這些處理能力,乙個真正的程式設計師的需要至關重要。

關於c++身後的設計目標如何影響語言行為的形成,以上介紹遠遠不夠。要想覆蓋所有的內容,將需要一整本書;方便的是,stroustrup寫了一本。這本書是 「the design and evolution of c++」 (addison-wesley, 1994),有時簡稱為 「d&e」。讀了它,你會了解到有哪些特性被增加到c++中,以什麼順序,以及為什麼。你還會知道哪些特性被放棄了,以及為什麼。你甚至可以了解到一些幕後故事,如dynamic_cast(參見條款39和m2)如何被考慮,被放棄,又被考慮,最後被接受 —- 以及為什麼。如果你理解c++有困難,d&e將為你驅散心頭的疑雲。

對於c++如何成為現在的樣子,」the design and evolution of c++」 提供了豐富的資料和見解,但它絕對不是正式的語言規格說明。對此你得求助於c++國際標準,一本令人印象深刻的長達700多頁的正式文字。在那兒你可以讀到象下面這樣刻板的句子:

乙個虛函式呼叫所使用的預設引數是表示物件的指標或引用的靜態型別所決定的虛函式所宣告的預設引數。派生類中的過載函式不獲取它過載的函式中的預設值。

這段話是條款38(」決不要重新定義繼承而來的預設引數值」)的基礎,但我期望我對這個論題的論述比上面的原文多少更讓人容易理解一些。

c++標準不是臨睡前的休閒讀物,而是你最好的依靠 —- 你的 「標準」 依靠 —- 如果你和其他人(比如,編譯器供貨商,或採用其它工具程式設計的開發人員)對什麼東西是或不是c++有分歧的話。標準的全部目的在於,為解決這類爭議提供權威資訊。

c++標準的官方名稱很咬口,但如果你需要知道,就得知道。這就是:international standard for information systems—-programming language c++。它由international organization for standardization (iso)第21工作組頒布。(如果你愛鑽牛角尖,它實際上是由iso/iec jtc1/sc22/wg21頒布的—-我沒有添油加醋)你可以從你的國家標準機構(在美國,是ansi,即american national standards institute)定購正式c++標準的副本,但c++標準的最新草稿副本 —- 和最終檔案十分相近(雖然不完全一樣)—- 在網際網路上是免費提供的。可以找到它的乙個好地方是 「the cygnus solutions draft standard c++ page」 (網際網路上變化速度很快,如果你發現這個**不能連線也不要奇怪。如果是這樣,搜尋引擎一定會幫你找到乙個正確的url。

我說過,」the design and evolution of c++」 對於了解c++語言的設計思想很有好處,c++標準則明確了語言的具體細節;如果在 「d&e千里之外的視野」 和 「c++標準的微觀世界」 之間存在承上啟下的橋梁那就太好了。教程應當適合於這個角色,但它們的視角往往偏向於標準,更側重於說明什麼是語言,而沒有解釋為什麼。

進入arm吧。arm是另一本書,」the annotated c++ reference manual」 (addison-wesley, 1990),作者是margaret ellis和bjarne stroustrup。這本書一出版就成為了c++的權威,國際標準就是基於arm(和已有的c標準)開始制定的。這幾年間,c++標準和arm中的說明在某些方面有分歧,所以arm不再象過去那樣具有權威性了。但它還是很具參考價值,因為它所說的大多數還是正確的;所以,在c++領域中,有些廠家還是堅持採用arm規範,這並不少見,畢竟,標準只是最近才定下來。

然而,使得arm真正有用的不是它的rm部分(the reference manual),而是a部分(the annotations):注釋。針對c++的很多特性 「為什麼」 要象現在這樣工作,arm提供了全面的解釋。這些解釋d&e中也有一些,但大多數沒有,你確實需要了解它們。例如,第一次碰到下面這段**,大部分人會為它發瘋:

class base ;

class derived: public base ;

derived *pd = new derived;

pd->f(10); // 錯誤!

問題在於derived::f隱藏了base::f,即使它們取的是不同的引數型別;所以編譯器要求對f的呼叫取乙個double*,而10這個數字當然不行。

這不很合理,但arm對這種行為提供了解釋。假設呼叫f時,你真的是想呼叫derived中的版本,但不小心用錯了引數型別。進一步假設derived是在繼承層次結構的下層,你不知道derived間接繼承了某個基類baseclass,而且baseclass中宣告了乙個帶int引數的虛函式f。這種情況下,你就會無意中呼叫了baseclass::f,乙個你甚至不知道它存在的函式!在使用大型類層次結構的情況下,這種錯誤會時常發生;所以,為了防患於未然,stroustrup決定讓派生類成員按名字隱藏掉基類成員。

順便指出,如果想讓derived的使用者可以訪問base::f,可以很容易地通過乙個using宣告來完成:

class derived: public base ;

derived *pd = new derived;

pd->f(10); // 正確,呼叫base::f

對於尚不支援using宣告的編譯器,另乙個選擇是採用內聯函式:

class derived: public base

virtual void f(double *pd);

}; derived *pd = new derived;

pd->f(10); // 正確,呼叫derived::f(int),

// 間接呼叫了base::f(int)

借助於d&e和arm,你會對c++的設計和實現獲得透徹理解,從而可能參悟到:有時候,看似巴洛克風格的建築外觀之後,是合理嚴肅的結構設計。(譯註:巴洛克風格的建築極盡富麗堂皇、粉裝玉琢,因而結構複雜,甚至有點怪異)將這些理解和c++標準的具體細節結合起來,你就矗立於軟體開發的堅實基礎之上,從而走向真正有效的c++程式設計之路。

條款50 提高對C 的認識

class base class derived public base derived pd new derived pd f 10 錯誤 名字查詢先於型別檢查,現在derived類中找到f函式,然後進行型別檢查,報錯 問題在於derived f隱藏了base f,即使它們取的是不同的引數型別 所...

對c語的認識

c語言是什麼。c語言是一門通用計算機程式語言,應用廣泛。c語言的設計目標是提供一種能以簡易的方式編譯 處理低階儲存器 產生少量的機器碼以及不需要任何執行環境支援便能執行的程式語言。怎樣學好c語言 1 學好c語言,你可以很好地應付任何一種程式設計工具。2 一定要多上機練習,通過程式了解相關知識。幾經反...

對「認識」的認識

很早就想談談關於 認識 的認識。這是乙個巨集大深刻的哲學問題。只是覺得沒有完全思考清楚,還以為觀點有些偏頗,擔心自己沒能力系統論述,就遲遲沒有動筆。但想到談論的問題本身就是乙個偏頗的問題,而且,我始終覺得,問題儘管偏頗,但卻不無道理。所以,提筆寫下這篇文字。正像思想的本質是不安一樣,認識的本質是片面...