引用型和指標很相像,任何引用可以完成的任務,指標也一樣可以完成,但是他的文法的確彌補了指標的很多缺陷。
引用和指標之間的共同點:
--- 都可以作為函數的參數和傳回值
--- 返回引用或地址(指標)的函數調用可以出現在賦值的任意一側
引用和指標之間的區別:
--- 引用是實際變數的邏輯別名
--- 引用在聲明的時候必須用一個實際變數來初始化
--- 引用在初始化後就不可改變
--- 不存在Null 參考
C++中的引用是其他變數的別名。聲明一個引用型變數需要給他一個初始值。在變數的生存周期中,該值不可改變。
可以用&運算子定義引用型變數。
例如:
int actualint;
int& otherint = actualint;
這兩條語句聲明了一個別名為otherint的整型變數actualint。對這兩個標識符的所有操作都會產生同樣的效果。
#include <iostream></p><p>////////////////////////////////////////<br />// The main() function.<br />////////////////////////////////////////<br />int main()<br />{<br /> int actualint = 123;<br /> int& otherint = actualint;</p><p> std::cout << actualint << std::endl;<br /> std::cout << otherint << std::endl;</p><p> otherint++;<br /> std::cout << actualint << std::endl;<br /> std::cout << otherint << std::endl;</p><p> actualint++;<br /> std::cout << actualint << std::endl;<br /> std::cout << otherint << std::endl;</p><p> return 0;<br />}
運行結果:
注意:
引用既不是原對象的副本,也不是指向原對象的指標。實際上,編譯器把他作為原對象的另外一個名字。
下面的代碼通過比較兩者的地址,說明了別名這個比喻是很恰當的。
#include <iostream></p><p>////////////////////////////////////////<br />// The main() function.<br />////////////////////////////////////////<br />int main()<br />{<br /> int actualint = 123;<br /> int& otherint = actualint;<br /> std::cout << &actualint << ' ' << &otherint;</p><p> return 0;<br />}
啟動並執行結果如下:
初始化引用:
和指標不同,引用型變數的值不可改變。引用時真實變數的別名,必須對其進行初始化(顯式的指定它的引用對象),除非滿足下列條件之一:
--- 引用型變數被聲明為外部的(extern),可以在任何地方對其進行初始化。
--- 引用型變數為類的成員,在建構函式裡對他進行初始化。
--- 引用型變數作為函式宣告中的形參,在函數調用時,用調用者的實參來進行初始化。
用引用來簡化複雜的運算式
當某些運算式需要從數組元素和結構中擷取對象時,可以利用引用來簡化複雜的運算式。特別是在為了得到某個特定元素而需要反覆使用一長串運算式時,引用顯得極為方便。
#include <iostream></p><p>// A Date structure.<br />struct Date<br />{<br /> int month, day, year;<br />};</p><p>// An Employee structure.<br />struct Employee<br />{<br /> int empno;<br /> char name[35];<br /> Date dates[3]; // hired, last review, terminated.<br /> float salary;<br />};</p><p>Employee staff[] =<br />{<br /> { 1, "Bill", {{12,1,88},{2,24,92},{5,5,95}}, 35000 },<br /> { 1, "Paul", {{10,3,87},{5,17,94},{3,7,96}}, 25000 },<br /> { 1, "Jim", {{ 9,5,80},{9,11,96},{0,0, 0}}, 42000 },<br /> { 0 }<br />};</p><p>////////////////////////////////////////<br />// The main() function.<br />////////////////////////////////////////<br />int main()<br />{<br /> Employee* pEmpl = staff;<br /> while (pEmpl->empno != 0)<br /> {<br /> for (int i = 0; i < 3; i++)<br /> {<br /> Date& rd = pEmpl->dates[i];<br /> std::cout << rd.month << '/'<br /> << rd.day << '/'<br /> << rd.year << " ";<br /> }<br /> std::cout << std::endl;<br /> pEmpl++;<br /> }</p><p> return 0;<br />}
運行結果如下:
用作函數形參的引用
引用常常被用作函數的形參。如果引用僅僅在於變數的範圍內,那麼幾乎沒什麼作用,直接使用變數的原名就可以了。
使用引用代替實參副本作為形參的優點:
--- 避免了傳遞大型資料結構帶來的額外開銷。
--- 無須像指標那樣使用*和->等運算子。
#include <iostream></p><p>// A big structure.<br />struct bigone<br />{<br /> int serno;<br /> char text[1000];<br />};</p><p>// Two function prototypes with a structure parameter.<br />void slowfunc(bigone p1); // Call by value.<br />void fastfunc(bigone& p1); // Call by reference.</p><p>////////////////////////////////////////<br />// The main() function.<br />////////////////////////////////////////<br />int main()<br />{<br /> static bigone bo = {123, "This is a BIG structure"};</p><p> // This call will take a while.<br /> slowfunc(bo);</p><p> // This call will be faster than the previous one.<br /> fastfunc(bo);</p><p> return 0;<br />}</p><p>////////////////////////////////////////<br />// A call-by-value function.<br />////////////////////////////////////////<br />void slowfunc(bigone p1)<br />{<br /> std::cout << p1.serno << std::endl;<br /> std::cout << p1.text << std::endl;<br />}</p><p>////////////////////////////////////////<br />// A call by reference function.<br />////////////////////////////////////////<br />void fastfunc(bigone& p1)<br />{<br /> std::cout << p1.serno << std::endl;<br /> std::cout << p1.text << std::endl;<br />}
運行結果如下:
以引用方式調用函數
當函數把引用作為參數傳遞給另外一個函數時,被調用函數將直接對調用者的參數副本進行操作,而不是產生一個局部的副本(傳遞變數本身是這樣的)。這稱為以引用方式調用,而把參數的值傳遞到被調用的函數內部的副本中則稱為以傳值方式調用。
#include <iostream></p><p>// Date structure.<br />struct Date<br />{<br /> int month, day, year;<br />};</p><p>// Function prototypes.<br />void display(const Date&, const char*);<br />void swapper(Date&, Date&);</p><p>////////////////////////////////////////<br />// The main() function.<br />////////////////////////////////////////<br />int main()<br />{<br /> // define two dates.<br /> static Date now = {2,23,90};<br /> static Date then = {9,10,60};</p><p> // Display the dates.<br /> display(now, "Now: ");<br /> display(then, "Then: ");</p><p> // Swap the dates and redisplay them.<br /> swapper(now, then);<br /> display(now, "Now: ");<br /> display(then, "Then: ");</p><p> return 0;<br />}</p><p>////////////////////////////////////////<br />// Swap the caller's dates.<br />////////////////////////////////////////<br />void swapper(Date& dt1, Date& dt2)<br />{<br /> Date save;<br /> save = dt1;<br /> dt1 = dt2;<br /> dt2 = save;<br />}</p><p>////////////////////////////////////////<br />// Display a Date object.<br />////////////////////////////////////////<br />void display(const Date& dt, const char* ttl)<br />{<br /> std::cout << ttl;<br /> std::cout << dt.month << '/'<br /> << dt.day << '/'<br /> << dt.year << std::endl;<br />}
啟動並執行結果如下:
作為函數傳回值的引用
當然函數返回一個引用時,對函數的調用可以出現在引用可以出現的任何位置,包括賦值的接收端。
#include <iostream></p><p>// A date structure.<br />struct Date<br />{<br /> int month, day, year;<br />};</p><p>// An array of dates.<br />Date birthdays[] =<br />{<br /> {12, 17, 37},<br /> {10, 31, 38},<br /> { 6, 24, 40},</p><p> {11, 23, 42},<br /> { 8, 5, 44},<br />};</p><p>////////////////////////////////////////<br />// A function to retrieve a date.<br />////////////////////////////////////////<br />const Date& getdate(int n)<br />{<br /> return birthdays[n-1];<br />}</p><p>////////////////////////////////////////<br />// The main() function.<br />////////////////////////////////////////<br />int main()<br />{<br /> int dt = 99;<br /> while (dt != 0)<br /> {<br /> std::cout << std::endl<br /> << "Enter date # (1-5, 0 to quit): ";<br /> std::cin >> dt;</p><p> if (dt > 0 && dt < 6)<br /> {<br /> const Date& bd = getdate(dt);<br /> std::cout << bd.month << '/'<br /> << bd.day << '/'<br /> << bd.year << std::endl;<br /> }<br /> }</p><p> return 0;<br />}
運行結果如下:
引用和指標使用場合的指到原則:
1.如果指向的變數可能不存在,那麼使用指標。對於指標參數,可以用空(null)地址表示變數的不存在;而Null 參考是不存在的。如果確信變數肯定存在,那麼就使用引用。
2.如果程式必須遍曆對象的數組,那麼應該考慮使用指標。這時,指標的算術運算子通常比引用使用的下標標記法更有效率。對於後者而言,程式需要使用2個變數:引用和下標;對於前者而言,只需要一個變數就夠了。
3.引用能完成的工作,指標也能完成。引用型變數對指標的一個改進是:引用型變數的值無法改變,但又可以通過指標的算術運算來得到一個新的對象地址,這樣減少了很多麻煩。一旦將一個引用型變數正確的初始化為指向某個對象後,就不能再讓他指向別的地方,特別是其不應該指向的位置。
4.引用可以避免使用指標得到對象所需要的複雜標記法。