再談“引用”
晚上又把Netbeans6.1給裝上了,不過不是用來做java的,是做C++的,唉,無奈啊,誰叫上學期給掛了呢。想想自己其實也挺酷,一張C++的卷子,全用C#來解答,在答到中間程序題時,不知咋的,叛逆心突然膨脹,覺得在紙張上寫程序很無聊,就寫了幾個“同上”,“… ...”,結果就……,不過老師其實還不錯,后來問他時,他說最后一題給了我滿分(只有這題有寫完整),這說明他還是沒有過分計較語言的。
話說回來,其實C++也不是那么可惡,雖然C#比它elegant了許多。復習起C++,還是比較容易接受的,不過有些地方不說還真是不注意,正好看到了C++中的引用,就隨便拉出word扯兩句。
在C#中,引用是指內存的地址,比如新建一個對象Person p = new Person();,那么p所保存的,就是Person實例(在托管堆上分配內存)的地址,而p本身,是棧上的一個變量。
那在C語言中呢,有指針的概念,在C++中又有引用的概念,感覺C++中的引用和C#中的引用還算是基本一樣的意思,但在C++的書中往往解釋很多,因為指針的存在。那指針變量和引用的區別在哪呢。
首先,指針不是指針變量,指針是內存地址,而指針變量,是一個儲存著這個地址的變量,就像前面C#中的Person p = new Person(),這個p其實就可以稱為一個指針變量,它首先是一個變量,然后它保存的值是一個內存地址(當然,C#中不會這么稱呼它的)。
而C++中的引用,其實是變量的“別名”,比如:int a = 10; 那么,a是在棧上開辟的一塊內存空間,存儲著10,而a的引用(別名)所存儲的內容,也就是a所在的內存空間的上整型值10,可以把引用用“別名”來代替,再用“別名”的字面意思來理解,其實就比較好理解了。a的別名,則可認為除了名字和a不一樣外,其它完全一樣,地址,存儲內容,都一樣。
a的別名(引用)是這樣定義的:
int &b = a; //定義a的引用b
從函數傳參可以更深刻的理解它,看:
void Swap(int a , int b);2
//…3
int c = 10;4
int d = 12;5
Swap(c, d);
當調用Swap (c, d)時,有一個copy的過程,在Swap函數體中的a和b,僅僅只是變量c和d的副本,它們存儲的內容相同,但所在的內存空間并不一樣。
再看:
void Swap (int *a, int *b);2
//
3
int c = 10;4
int d = 12;5
Swap(&c, &d);6

當調用Swap (&c, &d)時,一樣,還是有一個copy的過程,但和上面的又不一樣,上面copy的是變量,這里copy的是指針變量(存儲內存地址),也就是說,在調用時,它會創建兩個指針變量,然后把c和d的地址分別賦給它們,而在Swap函數體中執行時,就可以對這兩個指針變量進行操作,也就是說,我們可以從這兩個指針變量得到實參的地址,那么,改變實參的值當然沒有問題。但是有一點是需要注意的,這里“創建了兩個指針變量”。
再看:
Swap (int &a, int &b);2
//
3
int c = 10;4
int d = 12;5
Swap(c, d);
這里用上了別名,Swap函數接受兩個參數,它們是變量的引用(別名),當調用Swap (c, d)時,就不再有copy的過程了,在Swap函數體中,直接操縱著c和d,因為傳遞的是它們的別名,這就好比水言木是我的網名(別名),別人摔了水言木一巴掌,那就是實實在在地摔了我一巴掌。
說到這里,就轉過來看看C#中的ref關鍵字吧,看:
int Swap(ref int a, ref int b) { … }2
//
3
int c = 10;4
int d = 12;5
Swap(ref c, ref d);6

其實ref的作用和上面C++中的引用(別名)是一樣的,當用上了ref時,就不再有傳參時的參數拷貝過程了,而如果沒用ref,那在Swap函數體中的a和b,其實就是c和d的副本。
而C#中,是沒有指針這東東的,那它有沒有類似C++中傳遞指針的情況呢?有。看下面:
Swap(Person p) { … } //為了少打點字,這里就不考慮Swap函數的語義了2
//
3
Person person = new Person();4
Swap(person);
person是類的實例名(對象名),它所存儲的,就是實例在托管堆中的地址,如上面所說,我們可以認為它是C++中的指針變量,那么,當調用Swap (person)時,就有一個copy的過程:在棧上開辟一塊空間,存儲person的值(值是Person實例的地址),然后在Swap函數體中操作的p,其實是棧上的另一塊空間,因為它和實參person所存儲的內容一樣,都是實例的地址,所以,在函數中對p屬性的賦值可以改變實參person相應的屬性值,但是,如果在Swap中有一句p = new Person(),那么,之后的p,則是指向了另一塊堆上的空間(新Person實例的地址)。
而如果用的是ref:
Swap(ref Person p) {…}2
//
3
Person person = new Person();4
Swap(ref person);5

那么,傳參時就沒有了參數copy的過程,于是,若在Swap中進行p = new Person(),那也是會使實參的值(地址)改變,那原先的Person實例,就會成為一個等待GC來收集的垃圾了。
洋洋灑灑寫了不少字,到此結束。
相關文章:小記一次讓我誤會的引用傳參

浙公網安備 33010602011771號