C++ 是介於匯編語言與高級語言之間的一種“全能”語言。它的能力是其他任何基於VMA(馮-諾曼架構)計算機的高級程序設計語言無法望其項背的,而性能也只有C語言可與之伯仲。
然而長期以來,喜歡C++和憎恨C++的陣營,惡斗了三十多年,誰也說服不了誰。其中的一個重要原因是:C++的邏輯和語意難以分割,計算機學術界很難把它形式化(比如具有像Haskell那樣的數學美), 這和量子力學裡的不確定性類似,愛因斯坦就對此討厭之極。
這裡我不想評論兩方的對錯,但是我想就C++的一個最基本的概念,也是最重要的概念之一的“reference",作一番論述,看看是否說得通。
讀者如果讀過拙文“ http://blog.csdn.net/ly8838/article/details/38638491”,可能會對reference微妙的一面有所共鳴的。這裡我想進一步談談reference的一些細節。
要想敘述reference,我們不得不從更基本的定義 - 直接對象(direct object)說起.
C++中,直接對象是“常規變量”(normal variable), 具有“值語意”(value semantics),和rvalue 語意。 這還沒有引入reference,就已經陷入邏輯上“循環定義”的怪圈了。要想跳出,只有舉例:
long x;
MyClass m; // MyClass is a user defined class
上面x和m都是“直接變量”,它們在內存中的區域可以不同:可以在程序的靜態空間(全程變量),可以在工作堆棧內(自動變量),也可在動態空間內(間接地包含在母object中)。由於所在區域不同,這些直接變量對程序性能的特征影響很大(以後的博克會提及)。但是最重要的,是它們和傳統的“基本型變量(primitive type variable)”在語法和用法上的相似。這是C++為何會支持它的重要原因。
對於首先學習C#,JavaScript, 或其他現代語言的程序員來說,“直接變量”幾乎沒有對應的概念。而更加令人不解的是,在“動態空間(heap)”中,直接變量只能“間接”地存在。而能夠“直接使用”動態變量"的唯一方法只有“指針”和“reference”. 這裡又陷入了循環:解釋直接變量時,又無法繞開“指針”和“reference”。
那麼reference到底是什麼呢?看看微基的解釋,(http://en.wikipedia.org/wiki/Reference_(C%2B%2B)),它幾乎也是同意反復,最後只有用“比喻”來解釋。也就是說,不用“指針”,“內存地址”等概念就無法解釋。
那麼,通俗上的說法“reference 是變量的alias (同體異名?)”是否說得通呢?
我認為,對於初學者來說,alias可謂最好的“比喻”。請看:
int x = int(10); // line1
int & r = x; // line2: r is an alias of x
r++; // line3: x is now 11
r = 3; // line4: x is now 3
assert (&r == &x); // line5: r points to x
我們看到,上面的程序顯示,r 和 x 幾乎沒任何區別,好像是形影相隨,難分難捨。這正是C++的宗旨:讓reference的變量和直接變量具有“等同”的語法,用法。
作為初級程序員來說,知道到這個用法也就夠了,但是“一點點知識是危險的”。如果我們以為x 和 r 是一個東西,那就錯了:
首先,x 是“直接變量”,而r是間接變量,所以它們在語意上是完全不一樣的(編譯出來的代碼大相庭徑)。你可以說這與我無關,會應用就行了,這也不錯,不過並不能高枕無憂:在另一個環境裡,你可能就會因為不清楚object reference 和 direct object 的區別而出錯,或是寫出性能差別極大的程序。
從語意上看,line2 幾乎等於 r = &x (取x的地址),無怪乎許多人認為 reference 其實就是指針, 而且line5證明它的確指著它的“直接變量”。知道這一點,對於下列代碼很重要:
class X {…}
void myXFunction(X x) {…}
void myXFunction2(const X & x) {…}
如果認為X& 是 X 的“alias”,而且用法一樣, 那麼你可能不需要myXFunction2,但是如果你知道X&的語意和X * 一樣,你才會推論出myXFunction2的性能一般會比myXFunction好,特別是當X裡面包含大量“成員”時,myXFunction2不用copy 內容,只需copy地址 (我們說這是淺拷貝- shallow copy), 而myXFunction必須傳入的內容copy 到argument變量中(我們說這是深拷貝- deep copy)。
在這裡,語意蓋過了邏輯。const X &x 的用法,特別是語意,最好用指針來诠釋才說得過去。
好吧,那就說reference是指針吧,可是它又不能解決上面程序line4的用法:
因為對一個指針賦值會使得它改變指向。r 若為指針,line4 會使得 r 指向地址為 3 的內存元,這和 alias 的概念又風馬牛不相及。
幸運的是實際情況並非如此:r 沒變(指向沒變),倒是 x 變了,在這個用例中,對 r 的 alias 诠釋從語法和語意上都雙雙勝過了指針诠釋。
綜上所述,reference 就像一個具有“波粒二象性”的光子, 它具有“pointer-alias” 二象性,不從語法-用法-語意的三方面理解,無法認識 reference 的真谛。
如果僅有二象也就罷了,OOP (C++ 支持OOP)有一個重要的概念,叫 polymorphism, 說的是一個“變量”其實可以是同時代表“基類”和其衍生類(derived class):它既可以是A也可以是B(假設A是B的基類)(又是典型的量子悖論)。而這種 polymorphic 的變量,只能是指針和 reference,不可能是“直接變量”。這一特征又給 reference 加了另一頂帽子:polymorphic variable, 通俗說的話,它是具有同時擁有不同身份的“怪物”。這裡的詳情下次再談論。
為什麼polymorphic variable只能是指針和reference呢?我個人認為,這無法用形式邏輯和常規邏輯來解釋,只能用指針的性質和C++ 的object model內存結構來解釋 - 這又是一個語意層面才能自圓其說的概念,是C++量子特性的另一佐證。以後我會用專文來诠釋C++這一重大問題。
總之,一個reference 的概念,包含了三種完全不同的诠釋,可以俗稱為三位一體:
到此可以做個總結,本文宗旨不是搬弄詞匯,而是企圖從邏輯,數學上诠釋C++的一些基本概念,以便拋磚引玉,喚起你對C++的深層思考。
此文的結論是:
1)C++的一些基本概念不是形式邏輯和傳統數學可以定義得清楚的。只有從“語意”上(編譯目標代碼)和“物理”上(計算機內存的結構)才能诠釋。
2)C++的語意(程序的硬件表達),是理解C++的關鍵。其他的語言,如Java,C#, JavaScript等,更接近數理邏輯,不用太在意其“語意”,95%的都能理解。
3)不懂C++語意,對C++程序員的深化和提高,寫出高質量,高性能的C++程序,有著不容忽略的負面影響。
楊鐮:2014-8-18 西雅圖
hm格式文件下載: (好像是英文版的)其他的資料還有:
C~C++程序員實用大全(41.46M):
C++入門基礎教程(推薦 7.53M):
C/C++/C#程序員實用大全(精華版)(10.82M):
以上的我覺得都挺不錯,更多請自行網上搜索,推薦使用迅雷下載
另外,虛機團上產品團購,超級便宜