文章目錄
- C++ 引用的應用
- 1. 修改函數中傳遞的參數
- 2. 避免復制大型結構
- 3. for 循環中修改所有對象
- 4. for 循環中避免復制對象
- References vs Pointers
- 引用的限制
- 使用引用的優點
- 練習
- Quesition 1
- Question 2
- Question 3
- Question 4
- Question 5
- Question 6
如果一個變量被聲明為引用,那它就成了一個已有變量的別名。一個變量可以通過在聲明的時候加
&
而成為引用。
此外,還可以將引用變量定義為一種類型,它可以作為另一個變量的引用。&
用于表示變量或任何內存的地址。與引用變量關聯的變量,既可以通過變量名訪問,也可以通過與之關聯的引用變量訪問。
語法:
data_type &ref = variable;
例子:
// C++ Program to demonstrate
// use of references
#include <iostream>
using namespace std;int main()
{int x = 10;// ref is a reference to x.int& ref = x;// Value of x is now changed to 20ref = 20;cout << "x = " << x << '\n';// Value of x is now changed to 30x = 30;cout << "ref = " << ref << '\n';return 0;
}
輸出:
x = 20
ref = 30
C++ 引用的應用
C++中的引用有很多的應用,如下是其中的一些:
- 修改函數中傳遞的參數;
- 避免復制大型結構;
- for 循環中修改所有對象;
- for 循環中避免復制對象;
1. 修改函數中傳遞的參數
如果一個函數接收到了一個變量的引用,它可以修改這個變量的值。如下程序變量是使用引用交換的。
// C++ Program to demonstrate
// Passing of references as parameters
#include <iostream>
using namespace std;// Function having parameters as
// references
void swap(int& first, int& second)
{int temp = first;first = second;second = temp;
}// Driver function
int main()
{// Variables declaredint a = 2, b = 3;// function calledswap(a, b);// changes can be seen// printing both variablescout << a << " " << b;return 0;
}
輸出:
3 2
2. 避免復制大型結構
想象一下,一個函數必須接收一個大對象。如果我們沒有使用引用來傳遞,那么它的一個新副本就會被創建,這回導致CPU時間和內存的浪費。可以使用引用來避免這種情況。
struct Student {string name;string address;int rollNo;
}// If we remove & in below function, a new
// copy of the student object is created.
// We use const to avoid accidental updates
// in the function as the purpose of the function
// is to print s only.
void print(const Student &s)
{cout << s.name << " " << s.address << " " << s.rollNo<< '\n';
}
3. for 循環中修改所有對象
我們可以在每個循環中使用引用來修改所有元素。
// C++ Program for changing the
// values of elements while traversing
// using references
#include <iostream>
#include <vector>using namespace std;// Driver code
int main()
{vector<int> vect{ 10, 20, 30, 40 };// We can modify elements if we// use referencefor (int& x : vect) {x = x + 5;}// Printing elementsfor (int x : vect) {cout << x << " ";}cout << '\n';return 0;
}
輸出:
15 25 35 45
4. for 循環中避免復制對象
我們可以在每個循環中使用引用,以避免在對象很大時復制單個對象。
// C++ Program to use references
// For Each Loop to avoid the
// copy of objects
#include <iostream>
#include <vector>using namespace std;// Driver code
int main()
{// Declaring vectorvector<string> vect{ "geeksforgeeks practice","geeksforgeeks write","geeksforgeeks ide" };// We avoid copy of the whole string// object by using reference.for (const auto& x : vect) {cout << x << '\n';}return 0;
}
輸出
geeksforgeeks practice
geeksforgeeks write
geeksforgeeks ide
References vs Pointers
引用和指針都可以用于在一個函數中修改另一個函數的局部變量。當作為參數傳遞給函數或從函數返回時,它們都可以用來避免復制大對象,從而提高效率。盡管有上述相似之處,引用和指針之間還是有以下區別。
- 指針可以被聲明為
void
,但引用不可以int a = 10; void* aa = &a; // it is valid void& ar = a; // it is not valid
- 指針變量有n層/多層的間接,即單指針、雙指針、三指針。然而,引用變量只有一個間接層次。下面的代碼揭示了上述幾點:
輸出:// C++ Program to demonstrate // references and pointers #include <iostream> using namespace std;// Driver Code int main() {// simple or ordinary variable.int i = 10;// single pointerint* p = &i;// double pointerint** pt = &p;// triple pointerint*** ptr = &pt;// All the above pointers differ in the value they store// or point to.cout << "i = " << i << "\t"<< "p = " << p << "\t"<< "pt = " << pt << "\t"<< "ptr = " << ptr << '\n';// simple or ordinary variableint a = 5;int& S = a;int& S0 = S;int& S1 = S0;// All the references do not differ in their// values as they all refer to the same variable.cout << "a = " << a << "\t"<< "S = " << S << "\t"<< "S0 = " << S0 << "\t"<< "S1 = " << S1 << '\n';return 0; }
i = 10 p = 0x7ffecfe7c07c pt = 0x7ffecfe7c080 ptr = 0x7ffecfe7c088 a = 5 S = 5 S0 = 5 S1 = 5
- 引用變量不能更新;
- 引用變量是一個內部指針;
- 引用變量的聲明前面有
&
符號(但不要將其讀作“address of”)。
引用的限制
- 一個引用一旦被創建,它就不能再引用另一個對象;它不能被重置。這通常使用指針完成。
- 引用不能是NULL。指針經常用 NULL 來表示它沒有指向任何有效的東西。
- 引用必須在聲明的時候初始化,而指針沒有該限制。
由于上面的限制,C++中的引用不能用于實現如鏈表、樹等數據結構。Java 中,引用沒有上述限制,可以用于實現所有的數據結構。Java不需要指針的主要原因是引用功能更強大。
使用引用的優點
- 更安全:由于引用必須初始化,所以像野指針這樣的野引用不太可能存在。但仍然有可能存在不指向有效位置的引用(見下面練習中的第5和6題)
- 使用更方便:引用不需要解引用運算符來訪問值。它們可以像普通變量一樣使用。
&
運算符只有在聲明的時候需要。此外,對象引用的成員可以通過點運算符(.
) 訪問,而不像指針,需要箭頭運算符(->
) 才能訪問成員。
除了上述原因,還有一些地方如拷貝構造函數不能使用指針。在拷貝構造函數中必須使用引用傳遞實參,類似地,重載某些運算符如++
時必須使用引用。
練習
Quesition 1
#include <iostream>
using namespace std;int& fun()
{static int x = 10;return x;
}int main()
{fun() = 30;cout << fun();return 0;
}
輸出:
30
Question 2
#include <iostream>
using namespace std;int fun(int& x) { return x; }int main()
{cout << fun(10);return 0;
}
輸出:
./3337ee98-ae6e-4792-8128-7c879288221f.cpp: In function 'int main()':
./3337ee98-ae6e-4792-8128-7c879288221f.cpp:8:19: error: invalid initialization of non-const reference of type 'int&' from an rvalue of type 'int'cout << fun(10);^
./3337ee98-ae6e-4792-8128-7c879288221f.cpp:4:5: note: in passing argument 1 of 'int fun(int&)'int fun(int& x) { return x; }
Question 3
#include <iostream>
using namespace std;void swap(char*& str1, char*& str2)
{char* temp = str1;str1 = str2;str2 = temp;
}int main()
{char* str1 = "GEEKS";char* str2 = "FOR GEEKS";swap(str1, str2);cout << "str1 is " << str1 << '\n';cout << "str2 is " << str2 << '\n';return 0;
}
輸出:
str1 is FOR GEEKS
str2 is GEEKS
Question 4
#include <iostream>
using namespace std;int main()
{int x = 10;int* ptr = &x;int&* ptr1 = ptr;
}
輸出:
./18074365-ebdc-4b13-81f2-cfc42bb4b035.cpp: In function 'int main()':
./18074365-ebdc-4b13-81f2-cfc42bb4b035.cpp:8:11: error: cannot declare pointer to 'int&'int&* ptr1 = ptr;
Question 5
#include <iostream>
using namespace std;int main()
{int* ptr = NULL;int& ref = *ptr;cout << ref << '\n';
}
輸出:
timeout: the monitored command dumped core
/bin/bash: line 1: 34 Segmentation fault timeout 15s ./372da97e-346c-4594-990f-14edda1f5021 < 372da97e-346c-4594-990f-14edda1f5021.in
Question 6
#include <iostream>
using namespace std;int& fun()
{int x = 10;return x;
}int main()
{fun() = 30;cout << fun();return 0;
}
輸出:
0