【C++ 筆記】參考(Reference) - part 14 === 目錄(Table of Contents): [TOC] --- 很感謝你點進來這篇文章。 你好,我並不是什麼 C++、程式語言的專家,所以本文若有些錯誤麻煩請各位鞭大力一點,我極需各位的指正及指導!!本系列文章的性質主要以詼諧的口吻,一派輕鬆的態度自學程式語言,如果你喜歡,麻煩留言說聲文章讚讚吧! 簡介(Introduction) --- > 參考(Reference)是物件的別名(Alias),也就是替代名稱,對參考名稱存取時該有什麼行為,都參考了來源物件該有的行為,在 C++ 中,「物件」這個名詞,不單只是指類別的實例,而是指記憶體中的一塊資料。 所以參考變數是現存變數的另一個名字,將參考初始化為某個變數,就可以使用該參考名稱或變數名稱來指向變數。 參考常常與指標做比較,原因是他們的性質相同,同樣地,我們先從定義上來看: :::success 指標(Pointer): * 指標是一種變數,用來儲存其他變數的記憶體位址。指標可以直接對記憶體進行運算。 * 宣告時使用星號(`*`)來表示,例如:`int* ptr;` 表示 ptr 是一個指向整數的指標。 ::: :::info 參考(Reference): * 參考是另一個變數的別名,並且必須在宣告時初始化。參考可以直接對原始變數進行運算,不需要額外的解參考運算(Deference)。 * 宣告時使用 `&` 符號,例如:`int& ref = original;` 表示 `ref` 是 `original` 的參考。 ::: 筆者列以下表格比較兩者差異: | Items | Pointer | Reference | | -------- | -------- | -------- | | 初始化 | 可以不初始化,後續可重新指向其他變數 | 必須在宣告時初始化,且無法更改指向 | | NULL | 可以為空(nullptr),表示不指向任何有效地址 | 不能為空,必須始終指向一個有效的變數 | | 語法 | 使用星號(`*`)來宣告和解參考 | 使用 `&` 來宣告,如普通變數一般使用方式 | | 靈活性 | 可以指向不同型態的變數,包括指標本身 | 只能用作變數的別名,不支援指向其他參考或空值 | | 效能 | 可能會導致額外的解參考開銷 | 避免了不必要的資料複製,提升效能 | 有關參考的相關應用,如下四點: 1. 修改函數中傳遞的參數 2. 避免複製大型結構 3. 在 For Each 迴圈中修改所有物件 4. For Each 迴圈以避免物件的複製 Source:https://www.geeksforgeeks.org/references-in-cpp/ For Each Loop 相關資訊:https://zh.wikipedia.org/zh-tw/Foreach%E5%BE%AA%E7%8E%AF 其實,參考就像是一個人的綽號,一個人可以有很多的綽號,像是:彬彬、呆呆等等,無論有多少個綽號,這些都是指同一個人的意思,同一個人就是最原始的自己,所以是原始變數。 建立參考(Create a Reference) --- 假設我們有個原始變數叫做 `i`: ```cpp int i = 0; ``` 那麼我們可以替 `i` 宣告參考變數: ```cpp int& r = i; ``` `&` 運算子放置於資料型態後方可用於定義一個參考。 以下是一個範例: ```cpp= #include <iostream> using namespace std; int main() { int x = 10; // ref 為 x 的參考 int& ref = x; // x 的值現在變成 20 ref = 20; cout << "x = " << x << '\n'; // x 的值現在變成 30 x = 30; cout << "ref = " << ref << '\n'; return 0; } ``` Source:https://www.geeksforgeeks.org/references-in-cpp/ 輸出結果: ``` x = 20 ref = 30 ``` 先前我們有談過函數的參數傳遞,其中有所謂的傳參考呼叫,詳情請至我的筆記 part 11,「[傳送門點我](https://hackmd.io/@LukeTseng/BkR5_AFQJe)」。 藉參考回傳(Return by reference) --- 在 C++ 中,參考也可當成回傳值使用,如同指標的做法一般。 但是必須要注意以下這三點,才能好好使用 reference: 1. 作用域(Scope):當函數回傳一個參考時,必須確保被參考的物件在函數結束後仍然有效。回傳局域變數的參考是無效的,因為局域變數在函數結束後會被銷毀。 2. 修改原始數據:回傳的參考允許呼叫者直接修改原始數據,可能導致意外的副作用。如果不希望修改原始數據,應使用 const 修飾詞來回傳常數參考。 3. 靜態變數(static)的使用:可安全回傳靜態變數的參考,因為靜態變數在整個程式執行期間都存在。 以下是個範例: ```cpp= #include <iostream> using namespace std; double vals[] = {10.1, 12.6, 33.1, 24.1, 50.0}; // 回傳陣列中指定索引的元素的參考 double& setValues(int i) { return vals[i]; // 回傳第 i 個元素的參考 } int main() { cout << "改變前的值:" << endl; for (int i = 0; i < 5; i++) { cout << "vals[" << i << "] = " << vals[i] << endl; } // 改變第 2 和第 4 個元素 setValues(1) = 20.23; setValues(3) = 70.8; cout << "改變後的值:" << endl; for (int i = 0; i < 5; i++) { cout << "vals[" << i << "] = " << vals[i] << endl; } return 0; } ``` 輸出結果: ``` 改變前的值: vals[0] = 10.1 vals[1] = 12.6 vals[2] = 33.1 vals[3] = 24.1 vals[4] = 50 改變後的值: vals[0] = 10.1 vals[1] = 20.23 vals[2] = 33.1 vals[3] = 70.8 vals[4] = 50 ``` 程式碼解釋: ```cpp= setValues(1) = 20.23; setValues(3) = 70.8; ``` 由於函數中回傳的是 `vals[i]` 的參考,呼叫後可以視為以下的程式碼,結果是相同的: ```cpp= vals[1] = 20.23; vals[3] = 70.8; ``` 但是在這邊使用函數回傳參考值,可實現"避免了不必要的資料複製,提升效能"這句話。 總之,`setValues` 函數回傳 vals 陣列中指定索引的元素的參考。這樣可以直接通過這個參考來修改陣列中的值。 有關於作用域問題,以下是一個錯誤示範: ```cpp= #include <iostream> using namespace std; // 錯誤示範:回傳局域變數的參考 int& getLocalVariable() { int localVar = 42; // 局域變數 return localVar; // 回傳局域變數的參考 } int main() { int& ref = getLocalVariable(); // 嘗試獲取局域變數的參考 cout << "Local variable value: " << ref << endl; // 會出現未定義行為 return 0; } ``` 正確示範如下: ```cpp= #include <iostream> using namespace std; int& getLocalVariable() { static int localVar = 42; // 局域變數 return localVar; // 回傳局域變數的參考 } int main() { int& ref = getLocalVariable(); cout << "Local variable value: " << ref << endl; return 0; } ``` 參考資料 --- [Return by reference in C++ with Examples - GeeksforGeeks](https://www.geeksforgeeks.org/return-by-reference-in-c-with-examples/) [C++ 筆記 (Reference & Pointer) - HackMD](https://hackmd.io/@B7i0qMBLTyyyRp1nasdE-Q/ryfTY48qd) [參考](https://openhome.cc/Gossip/CppGossip/Reference.html) [References in C++ - GeeksforGeeks](https://www.geeksforgeeks.org/references-in-cpp/) [C++ 把引用作为返回值 | 菜鸟教程](https://www.runoob.com/cplusplus/returning-values-by-reference.html) [C++ 引用 | 菜鸟教程](https://www.runoob.com/cplusplus/cpp-references.html)
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up