程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 對C++中引用的補充說明(實例)

對C++中引用的補充說明(實例)

編輯:關於C++
#include <iostream>
#include <string>
using namespace std;
void main(int argc,char* argv[])
{
int a=10;
int b=20;
int &rn=a;
cout<<rn<<"|"<<a<<endl;
cout<<&rn<<"|"<<&a<<endl;//c++中是無法取得應用的內存地址的,取引用的地址就是取目標的地址!
rn=b;//把引用指向另一個目標----變量b
cout<<&rn<<"|"<<&a<<"|"<<&b<<endl;
rn=100;//試圖改變b的值
cout<<a<<"|"<<b<<endl;//輸出修改後的結果
cin.get();
}

由於引用本身就是目標的一個別名,引用本身的地址是一個沒有意義的值,所以在c++中是無法取得引用的內存地址的。取引用的地址就是取目標的地址,c++本身就根本不提供獲取引用內存地址的方法。

引用一單初始化,就不在能夠被指向其它的目標,雖然編譯不會出錯,但操作是不起作用的,實際上還是指向最先指向的目標。

上面代碼中的rn=b實際在計算機看來就是a=b,所以修改的還是a的值。

#include <iostream>
#include <string>
using namespace std;
void main(int argc,char* argv[])
{
int a=10;
void &rn=a;// 錯誤的,void即無類型的類型
int a[100];
int &ra[100]=a;//錯誤,不能聲明引用數組
cin.get();
}

上面的兩錯誤要記住引用的特性,void修飾是不能夠聲明引用的,引用是不能夠聲明數組的,即不能夠聲明引用數組。

下面我們要說一下,也是補充中最重要最需要掌握的內容,也是對傳統函數操作的內存狀態的一個補充學習。

下面我們來看一個例子:

#include <iostream>
#include <string>
using namespace std;

float c;
float test(float,float);
void main(int argc,char* argv[])
{
float pn=test(3.0f,1.2f);
cout<<pn;
cin.get();
}

float test(float a,float b)
{
c=a*b;
return c;
}

在上面的代碼中我們可能我們可能以為函數返回的就是c變量,呵呵。這麼想可能就錯了,普通情況下我們在函數內進行普通值返回的時候在內存棧空間內其實是自動產生了一個臨時變量temp,它是返回值的一個副本一個copy,函數在return的時候其實是return的這個臨時產生的副本。

數據在內存中的情況如下圖:

上圖明確表示了副本領事變量的情況。

下面我們再來看一種情況,就是把返回值賦給引用:

#include <iostream>
#include <string>
using namespace std;
float c;
float test(float,float);
void main(int argc,char* argv[])
{
float &pn=test(3.0f,1.2f);//警告:返回的將是臨時變量,pn引用將成為臨時變量的別名!
cout<<pn;
cin.get();
}
float test(float a,float b)
{
c=a*b;
return c;
}

float &pn=test(3.0f,1.2f);這句在bc中能夠編譯通過,因為bc擴展設置為臨時變量設置引用,那麼臨時變量的生命周期將和引用的生命周期一致,但在vc中卻不能通過編譯,因為一但test()執行過後臨時變量消失在棧空間內,這時候pn將成為一個沒有明確目標的引用,嚴重的時候會導致內存出錯。

它在內存中的情況見下圖:

我們在圖中看到,由於函數仍然是普通方法返回,所以仍然會有一個副本臨時變量產生,只不過,這一次只是返回一個目標地址,在main中目標地址被賦予了引用pn。

下面我們再看一種情況,這是返回引用給變量的情況:

#include <iostream>
#include <string>
using namespace std;
float c;
float& test(float,float);
void main(int argc,char* argv[])
{
float pn=test(3.0f,1.2f);
cout<<pn;
cin.get();
}
float &test(float a,float b)
{
c=a*b;
return c;
}

這種返回引用給變量的情況下,在內存中,test()所在的棧空間內並沒有產生臨時變量,而是直接將全局變量c的值給了變量pn,這種方式是我們最為推薦的操作方式,因為不產生臨時變量直接賦值的方式可以節省內存空間提高效率,程序的可讀性也是比較好的。

它在內存中的情況見下圖:

最後的一種情況是函數返回引用,並且發值賦給一個引用的情況:

#include <iostream>
#include <string>
using namespace std;
float c;
float& test(float,float);
void main(int argc,char* argv[])
{
float &pn=test(3.0f,1.2f);
cout<<pn;
cin.get();
}
float &test(float a,float b)
{
c=a*b;
return c;
}

這種情況同樣也不產生臨時變量,可讀和性能都很好,但有一點容易弄錯,就是當c是非main的局部變量或者是在堆內存中臨時開辟後來又被fee掉了以後的區域,這種情況和返回的指針是局部指針的後果一樣嚴重,會導致引用指向了一個不明確的地址,這種情況在內存中情況見下圖:

由於這種情況存在作用域的問題,故我們推薦采用第三種方式處理。

接下來我們說幾個利用引用作為左值參與計算的例子,這一點一非常重要,對於理解返回引用的函數是非常有幫助的。

#include <iostream>
#include <string>
using namespace std;
float c;
float& test(float,float);
void main(int argc,char* argv[])
{
float &pn=test(3.0f,1.2f);
cout<<pn<<endl;
test(3.0f,1.2f)=12.1;//把函數作左值進行計算!
cout<<pn;
cin.get();
}
float &test(float a,float b)
{
c=a*b;
return c;
}

通常來說函數是不能作為左值,因為引用可以做為左值,所以返回引用的函數自然也就可以作為左值來計算了。

在上面的代碼中:

float &pn=test(3.0f,1.2f);

進行到這裡的時候pn已經指向到了目標c的地址了。

接下來運行了

test(3.0f,1.2f)=12.1;

把函數作左值進行計算,這裡由於test是返回引用的函數,其實返回值返回的地址就是c的地址,自然c的值就被修改成了12.1。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved