C++小結--引用
1 什麼是引用
引用就是給已知的一個變數起了一個別名,引用引入了物件的一個同義詞。定義引用的表示方法與定義指標相似,只是用&代替了*。引用(reference)是c++對c語言的重要擴充。引用就是某一變數(目標)的一個別名,對引用的操作與對變數直接操作完全一樣。其格式為:型別 &引用變數名 = 已定義過的變數名。
列如:int a = 10; int &b = a;
那麼b也等於10。b和a其實是一塊記憶體。
我們放在具體的程式碼中驗證一下:
#include <iostream>
using namespace std;
int main()
{
cout << "引用測試例子\n";
int a = 123;
int &b = a; //引用的實質就是給一個地址起多個別名 注意和指標的區別
//同一塊記憶體空間有兩個變數的名字 a b 改變a b也跟著改變
b = 43;
cout << "b = " << b << endl;
cout << "&b = " << &b << endl;
cout << "&a = " << &a << endl;
system("pause" );
return 0;
}
輸出結果如下:
引用測試例子
b = 43
&b = 0095FA20
&a = 0095FA20
請按任意鍵繼續. . .
2 引用的特點
1 一個變數可以有多個引用
2 引用必須初始化
3 引用只能在初始化的時候引用一次,不能轉而引用其他的變數。
3 引用的幾種用法
3.1 基礎引用
void fun()
{
int a = 1;
int& b = a;
cout<<"a:address->" <<&a<< endl;
cout <<"b:address->" <<&b<< endl;
a = 2;
b = 3;
int& c = b;// 引用一個引用變數,別名的別名
c = 4;
}
3.2 常量引用
void fun2()
{
int d1 = 4;
const int & d2 = d1;
d1 = 5;//d1改變,d2的值也會改變。
//d2 = 6;//不能給常量(不能被修改的量)賦值。
const int d3 = 1;
const int & d4 = d3;
//int&d5 = d3;
const int & d6 = 5;//常量具有常性,只有常引用可以引用常量
double d7 = 1.1;
//int& d8 = d7;//d7是double型別,d8是int,d7賦值給 d8時要生成一個臨時變數
//也就是說d8引用的是這個帶有常性的臨時變數,所以不能賦值。
const int& d9 = d7;
}
3.3 引用作為引數
這裡引用作為引數和傳址呼叫相似,我們 舉個交換兩個數的例子來說明一下。
1.【值傳遞】如果形參為非引用的傳值方式,則生成區域性臨時變數接收實參的值
/*值傳遞的方式無法實現交換,因為傳參時對於引數left和right拷貝一臨時副本,交換的是副本值,因為其是臨時變數函式退出,變數銷燬,並不會影響外部left和right的值,所以修改失敗 */
void Swap (int left, int right)
{
int temp = left;
left = right ;
right = temp ;
}
2.【引用傳遞】如果形參為引用型別,則形參是實參的別名。
/*使用引用的話,不做臨時拷貝,&的使用說明此處只是原引數的另一個名字而已,所以修改時直接在原引數的基礎上修改變數值,所以交換成功*/
void Swap (int& left, int& right)
{
int temp = left;
right = left ;
left = temp ;
}
3.【指標傳遞】
/*傳入的是地址,因為地址是唯一的,所以指標通過地址的訪問進而可修改其內容,修改成功 */
void Swap (int* pLeft, int* pRight)
{
int temp = *pLeft;
*pLeft = *pRight;
*pRight = temp;
}
3.4 引用作為返回值
引用作為返回值可以將一個函式當左值。
#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 << "] = ";
cout << vals[i] << endl;
}
setValues(1) = 20.23; // 改變第 2 個元素
setValues(3) = 70.8; // 改變第 4 個元素
cout << "改變後的值" << endl;
for ( int i = 0; i < 5; i++ )
{
cout << "vals[" << i << "] = ";
cout << 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
當返回一個引用時,要注意被引用的物件不能超出作用域。所以返回一個對區域性變數的引用是不合法的,但是,可以返回一個對靜態變數的引用。
int& func() {
int q;
//! return q; // 在編譯時發生錯誤
static int x;
return x; // 安全,x 在函式作用域外依然是有效的
}
4 使用引用需要注意的地方
(1)&在這裡不是求地址運算,而是起標識作用。
(2)型別識別符號是指目標變數的型別。
(3)宣告引用時,必須同時對其進行初始化。
(4)引用宣告完畢後,相當於目標變數名有兩個名稱,即該目標原名稱和引用名,且不能再把該引用名作為其他變數名的別名。
(5)對引用求地址,就是對目標變數求地址。即引用名是目標變數名的一個別名。引用在定義上是說引用不佔據任何記憶體空間,但是編譯器在一般將其實現為const指標,即指向位置不可變的指標,所以引用實際上與一般指標同樣佔用記憶體。
(6)不能建立引用的陣列。因為陣列是一個由若干個元素所組成的集合,所以無法建立一個由引用組成的集合,但是可以建立陣列的引用。
(7)引用常見的使用用途:作為函式的引數、作為函式的返回值(注意作為返回值時,不能返回一個臨時變數的引用)。
5 引用和指標的異同點
5.1 相同點
兩者都是地址的概念,指標指向一塊兒記憶體,其內容為所指記憶體的地址;引用是某塊兒記憶體的別名。
5.2 不同點
1指標是一個實體,而引用僅是個別名;
2 引用使用時無需解引用(*),指標需要解引用;
3 引用只能在定義時被初始化一次,之後不可變;指標可變;
4 引用不能為空,指標可以為空;
5 “sizeof 引用”得到的是所指向的變數(物件)的大小,而“sizeof 指標”得到的是指標本身(所指向的變數或物件的地址)的大小;
6 指標和引用的自增(++)運算意義不一樣;
7 從記憶體分配上看:程式為指標變數分配記憶體區域,而引用不需要分配記憶體區域。
感謝:http://www.runoob.com/cplusplus/returning-values-by-reference.html
https://blog.csdn.net/xiao__tian__/article/details/51814617