【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
Sign in via Google
Sign in via Facebook
Sign in via X(Twitter)
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
Continue with a different method
New to HackMD?
Sign up
By signing in, you agree to our
terms of service
.