晚上又把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 a = 10;
int &b = a; //定義a的引用b
從函數傳參可以更深刻的理解它,看:
1void Swap(int a , int b);
2//…
3int c = 10;
4int d = 12;
5Swap(c, d);
當調用Swap (c, d)時,有一個copy的過程,在Swap函數體中的a和b,僅僅只是變數c和d的副本,它們儲存的內容相同,但所在的記憶體空間並不一樣。
再看:
1void Swap (int *a, int *b);
2//
3int c = 10;
4int d = 12;
5Swap(&c, &d);
6
當調用Swap (&c, &d)時,一樣,還是有一個copy的過程,但和上面的又不一樣,上面copy的是變數,這裡copy的是指標變數(儲存記憶體位址),也就是說,在調用時,它會建立兩個指標變數,然後把c和d的地址分別賦給它們,而在Swap函數體中執行時,就可以對這兩個指標變數進行操作,也就是說,我們可以從這兩個指標變數得到實參的地址,那麼,改變實參的值當然沒有問題。但是有一點是需要注意的,這裡“建立了兩個指標變數”。
再看:
1Swap (int &a, int &b);
2//
3int c = 10;
4int d = 12;
5Swap(c, d);
這裡用上了別名,Swap函數接受兩個參數,它們是變數的引用(別名),當調用Swap (c, d)時,就不再有copy的過程了,在Swap函數體中,直接操縱著c和d,因為傳遞的是它們的別名,這就好比水言木是我的網名(別名),別人摔了水言木一巴掌,那就是實實在在地摔了我一巴掌。
說到這裡,就轉過來看看C#中的ref關鍵字吧,看:
1int Swap(ref int a, ref int b) { … }
2//
3int c = 10;
4int d = 12;
5Swap(ref c, ref d);
6
其實ref的作用和上面C++中的引用(別名)是一樣的,當用上了ref時,就不再有傳參時的參數拷貝過程了,而如果沒用ref,那在Swap函數體中的a和b,其實就是c和d的副本。
而C#中,是沒有指標這東東的,那它有沒有類似C++中傳遞指標的情況呢?有。看下面:
1Swap(Person p) { … } //為了少打點字,這裡就不考慮Swap函數的語義了
2//
3Person person = new Person();
4Swap(person);
person是類的執行個體名(對象名),它所儲存的,就是執行個體在託管堆中的地址,如上面所說,我們可以認為它是C++中的指標變數,那麼,當調用Swap (person)時,就有一個copy的過程:在棧上開闢一塊空間,儲存person的值(值是Person執行個體的地址),然後在Swap函數體中操作的p,其實是棧上的另一塊空間,因為它和實參person所儲存的內容一樣,都是執行個體的地址,所以,在函數中對p屬性的賦值可以改變實參person相應的屬性值,但是,如果在Swap中有一句p = new Person(),那麼,之後的p,則是指向了另一塊堆上的空間(新Person執行個體的地址)。
而如果用的是ref:
1Swap(ref Person p) {…}
2//
3Person person = new Person();
4Swap(ref person);
5
那麼,傳參時就沒有了參數copy的過程,於是,若在Swap中進行p = new Person(),那也是會使實參的值(地址)改變,那原先的Person執行個體,就會成為一個等待GC來收集的垃圾了。
洋洋洒洒寫了不少字,到此結束。
相關文章:小記一次讓我誤會的引用傳參