1. 程式人生 > >7.2.2 引用形參、const類形參(重要)

7.2.2 引用形參、const類形參(重要)

簡介

(記住了,很重要,形參是const引用和非const引用的區別)

  • 可以使用指標來修改實參的值,也可以使用非const引用來修改實參的值。

  • 使用const 型別的引用的好處:

    • 不需要複製實參時,可以用引用型別,所有實參過大時用引用類形參,提高效率;

    • 又因為是const型別的引用,所以不能通過引用來修改實參的值

    • 非const引用只能繫結到與該引用同類型的物件;

一般情況下,將不需要修改的引用形參定義為const引用,普通的非const引用形參在使用時不太靈活,因為這樣的形參不能用字面值或產生右值的表示式實參初始化。

少用非const引用類形參,一般定義引用時最好加上const(記住了!!!!)

============================================================================================

導讀:

  1. 當我們呼叫一個函式時,第一件事就是建立形參的那兩個變數,並將這兩個變數初始化為呼叫函式時傳遞的實參值。
  2. 當我們使用普通的形參(非引用類形參)時,實參對形參的初始化就是直接執行復制操作,將實參的值複製給形參。在本節的形參時會討論到這個問題,就是直接執行復制有時候會效率很低—(7.1節)

  3. 複製實參並不是在所有的情況下都適合,不適宜複製實參的情況如下,在如下的情況中,有效的解決辦法是將形參定義為引用或指標型別:

    1. 當需要在函式中修改實參的值時;
    2. 當需要以大型物件作為實參傳遞時,對實際應用而言,複製物件所付出的時間和儲存空間代價往往過大;
    3. 當沒有辦法實現物件的複製時(13章)。—-(7.2節)

一、引用形參

1、使用指標來修改實參的值,也可以使用非const引用來修改實參的值。**

void swap(int v1,int v2)
{int temp;
temp=v2;
v2=v1;
v1=temp;
//形參v1和v2並不會長期存在
//這個函式是想改變實參的值,但是沒有辦法改變,執行swap時,只交換了其實參的區域性副本,而傳遞給swap的實參並沒有修改。
}
int main(){
int
i=0; int j=20; cout<<"Before swap():"<<i<<" "<<j<<endl; swap(i,j);//呼叫上面定義的swap函式,i和j的值並沒有修改 cout<<"after swap():"<<i<<" "<<j<<endl; return 0; }
//如果想要修改i和j 的值,可以將形參設定為引用型別
void swap(int &v1,int &v2)
{int temp;
temp=v2;
v2=v1;
v1=temp;}
//與所有引用一樣,引用形參直接關聯到其所繫結的物件,而並非這個物件的副本。
定義引用時,必須用與該引用繫結的物件初始化該引用。
//當呼叫swap(i,j) 函式時,形參v1只是物件i的另一個名字,修改v1的值就是修改i的值。

//將引用當實參與將指標當實參具有一樣的效果
//將引用當實參與將指標當實參具有一樣的效果
void swap(int *v1,int *v2)
{int temp;
temp=*v2;
*v2=*v1;
*v1=temp;}

//main函式裡面的函式呼叫寫成swap(&i,&j)

2、使用引用形參返回額外的資訊

沒有看懂!!!!!!!

  • 函式只能返回單個值,但有些時候,函式有不止一個的內容需要返回,例如定義一個find_val函式,在一個整型vector物件的元素中搜索某個特定值,如果找到滿足要求的元素,則返回指向該元素的迭代器;
  • 否則返回一個迭代器,指向該vector物件的end操作返回的元素。

  • 此外,如果該值出現了不止一次,我們還希望函式可以返回其出現的次數,在這種情況下,返回的迭代器應該指向具有要尋找的值得第一個元素。

如何定義既返回一個迭代器又返回出現次數的函式呢?
我們可以定義一種包含一個迭代器和一個計數器的新型別。或者給find_val傳遞一個額外的引用實參,用於返回出現次數的統計結果:

//函式返回型別是vector<int>::const_iterator,返回一個迭代器
//函式型別是vector<int>::const_iterator
//函式名是find_val
//有四個形參
vector<int>::const_iterator find_val(
vector<int>::const_iterator beg,//第一個元素
vector<int>::const_iterator end,//
int value,                     //我們要的值
vector<int>::size_type &occurs//出現的次數
)  
{
//函式體開始
vector<int>::const_iterator res_iter=end;
occurs=0;
for(;beg!=end;++beg)
  if(*beg==value) { 
   if(res_iter==end)
   ret_iter=beg;
   ++occurs;
}
return res_iter;//返回的是
}
it=find_val(ivec.begin(),ivec.end(),42,ctr);
//呼叫後,ctr的值將是42出現的次數,如果42在ivec中出現了,則it將指向其第一次出現的位置;
//否則,it的值為ivec.end(),而ctr則為0、

3、利用const引用避免複製

  • 在向函式傳遞大型物件時,需要使用引用形參,這是引用形參適用的另一種情況,但是對於大部分類型別或者大型陣列,它的效率太低了。(13章學到某些類型別是無法複製的,使用引用形參,函式可以直接訪問實參物件,而無須複製它)

  • const 引用

    • const引用是指向const物件的引用;
    • 非const引用只能繫結到與該引用同類型的物件;
    • const引用則可以繫結到不同但相關的型別的物件或繫結到右值
const int ival=1024;
const int &refval=ival;//可以,引用和被引用物件都是const型別
int &ref2=ival;//不可以
//可以讀取但是不能修改refval,因此對refval的賦值都是不合法的,不能直接對ival賦值,因此不能通過使用refval來修改ival。const引用只能繫結到與該引用同類型的物件;
const引用則可以繫結到不同但相關的型別的物件或繫結到右值

注意:

  1. 避免複製的意思是不是就是說,實參在給形參初始化的時候將值複製給形參;

  2. 因為如果是一般的形參(非引用),那麼在呼叫函式的時候,形參的初始化時是將實參的值複製給了形參;

  3. 可是在實參很長的情況下,複製操作的效率太低了,這時候我們就可以使用引用類的形參;

  4. 而且有時候(13章)是沒有辦法複製的

//這個函式需要訪問每個string物件的size,但不必修改這些物件所以用const型別形參。
//由於string物件相當長,所有我們希望避免複製操作,使用const引用就可以避免將實參值複製給形參;
//每一個形參都是const string型別的引用,因為形參是引用,所有不復制實參;
//又因為形參時const引用,所有函式不能使用該引用來修改實參
bool isShorter(const string &s1,const string &s2){
return s1.size()<s2.size();
}

使用const引用形參的好處:

  1. 因為是引用型別,所有實參過大時,不需要複製實參,提高效率;

  2. 又因為是const型別的引用,所有不能通過引用來修改實參的值(在一般情況下非const類的引用,因為引用是別名,是能夠通過引用來修改實參的值。7.2.1節)

4、更靈活的指向const的引用

前面提到的:
- 非const引用只能繫結到與該引用同類型的物件;

  • const引用則可以繫結到不同但相關的型別的物件或繫結到右值

    • 如果函式具有普通的非const引用形參,則顯然不能通過const物件進行呼叫,因為此時函式可以修改傳遞進來的物件,這樣就違背了實參的const特性;

    • 呼叫這樣的函式時,傳遞一個右值或具有需要轉換的型別的物件同樣是不允許的。

    • 應該將不需要修改的引用形參定義為const引用,普通的非const引用形參在使用時不太靈活,這樣的形參既不能用字面值或產生右值的表示式實參初始化。

int incr(int &val){

return ++val;
}
int main()
{
short v1=0;
const int v2=42;
int v3=incr(v1);//錯誤!!!v1不是int型別
v3=incr(v2);//錯誤!!!v2是const型別
v3=incr(0);//錯誤!!!0不是一個物件名
v3=incr(v1+v2);//錯誤!!!只有一個形參
int v4=incr(v3);//可以,型別相同!!!!都不是const

}
//不是很懂
string::size_type find_char(string &s,char c){
 string::size_type i=0;
 while(i!=s.size()&&s[i]!=c)
 ++i;
 return i;
}

//這個函式的問題是將其string型別的實參當做普通(非const)的引用,儘管函式並沒有修改這個形參的值,這樣的定義帶來的問題是不能通過字串字面值來呼叫這個函式(因為非const引用形參只能與完全同類型的非const物件關聯)。可更正為const string&s

if(find_char("hello world",'o'))//會導致編譯問題
//雖然字串字面值可以轉換為string物件,但上述呼叫仍然會導致編譯失敗
//即使程式本身沒有const物件,而且只使用string物件(而並非字串字面值或產生string物件的表示式)呼叫find_char函式,編譯階段仍然會出現問題。
//如下,可能有另外一個函式is_sentence 呼叫find_char來判斷一個string物件是否是句子:
bool is_sentence (const string &s){
return (find_char(s,',')==s.size() -1);
}
//函式is_sentence中的find_char的呼叫是一個編譯錯誤,傳遞進is_sentence的形參時指向const string物件的引用,不能將這種型別的引數傳遞給find_char

5、形參—–指向指標的引用

通過定義變數的引用可以實現實參值的變化,通過定義一個指標的引用(指標別名)可以實現實參指標的變化。

void ptrswap(int *&v1,int *&v2){
int *tmp=v2;
v2=v1;
v1=tmp;
}

//形參 int *&v1定義從右到左,理解是首先v1是一個引用,與指向int型物件的指標的別名。
也就是說v1只是傳遞進ptrswap函式的任意指標的別名。
int main()
{
   int  i=10;
   int j=20;
   int *pi=&i;
   int *pj=&j;
   cout<<*pi<<" "<<*pj<<endl;
   ptrswap(pi,pj);
   cout<<*pi<<" "<<*pj<<endl;
   return 0;
}

//輸出:
//10  20
// 20  10
即指標的值交換了,換句話說現在pi指向j,pj指向i。 

銜接下一節

習題7.12 什麼時候用指標形參??

當函式需要處理陣列且函式體不依賴於陣列的長度時應使用指標形參,其他情況下應使用引用形參。

相關推薦

7.2.2 引用const重要

簡介 (記住了,很重要,形參是const引用和非const引用的區別) 可以使用指標來修改實參的值,也可以使用非const引用來修改實參的值。 使用const 型別的引用的好處: 不需要複製實參時,可以用引用型別,所有實參過大時用引用類形參,提高效率

前端常用外掛工具庫彙總

前言 在開發中,我們經常會將一些常用的程式碼塊、功能塊進行封裝,為的是更好的複用。那麼,被抽離出來獨立完成功能,通過API或配置項和其他部分互動,便形成了外掛。 下面這些是我在工作中積累的一些常用的前端開源外掛,這裡只是羅列出來,詳細的用法各個外掛官網或者Gayhub都有介紹。注意:往往一個解決方案會

前端常用外掛工具庫彙總

前言 對本文感興趣可以先加個收藏,也可以轉發分享給身邊的小夥伴,以後遇到類似的場景就來看看具體的外掛及其用法。 上一篇《前端常用外掛、工具類庫彙總(上)》內容摘要: 動畫庫 滾動庫 輪播圖 滾屏 彈出框 訊息通知 下拉框 級聯選擇器

前端常用外掛工具庫彙總

前言 在開發中,我們經常會將一些常用的程式碼塊、功能塊進行封裝,為的是更好的複用。那麼,被抽離出來獨立完成功能,通過API或配置項和其他部分互動,便形成了外掛。 下面這些是我在工作中積累的一些常用的前端開源外掛,這裡只是羅列出來,詳細的用法各個外掛官網或者Gayhub都有介紹。注意:往往一個

方法例項方法靜態方法詳細詮釋重要

何時用靜態方法,何時用例項方法? 先說例項方法,當你給一個類寫一個方法,如果該方法需要訪問某個例項的成員變數時,那麼就將該方法定義成例項方法。一類的例項通常有一些成員變數,其中含有該例項的狀態資訊。而該方法需要改變這些狀態。那麼該方法需要宣告成例項方法。 靜態方法正好相反,它不需要訪問某個例項的成員變數,它不

做一個簡單的銀行賬戶演示程式。 1定義一個賬戶,包含使用者名稱密碼餘額等屬性存錢取錢等方法。 (2)定義一個銀行,包含銀行名賬戶列表等屬性,開賬戶查賬戶的功能。賬戶列表可以使用集

做一個簡單的銀行、賬戶演示程式。 (1)定義一個賬戶類,包含使用者名稱、密碼、餘額等屬性、存錢、取錢等方法。 (2)定義一個銀行類,包含銀行名、賬戶列表等屬性,開賬戶、查賬戶的功能。賬戶列表可以使用

OpenStack-M版(Mitaka)搭建基於Centos7.2+++十Openstack物件儲存服務swift完成安裝

十、Openstack物件儲存服務(swift)完成安裝 一、啟動服務 1.在控制節點節點上,啟動物件儲存代理服務及其依賴服務,並將它們配置為隨系統啟動 systemctl enable opens

OpenStack-M版(Mitaka)搭建基於Centos7.2+++十Openstack物件儲存服務swift

十、Openstack物件儲存服務(swift)上 配置:我在計算節點添加了兩塊硬碟(sdb,sdc)用來當儲存用,在我這搭建中計算節點也就是儲存節點了,原因電腦無法拉動更多虛擬幾所以咯。。。 簡單介紹: swift主要有四個元件:swift-proxy-serve

2NIO--緩沖區Buffer

不可 split 限制 特定 oca cde 下一個 圖片 all 緩沖區(BUffer) 緩沖區(Buffer):一個用於特定基本數據類型的容器。由 java.nio 包定義的,所有緩沖區都是 Buffer 抽象類的子類。 Java NIO 中的 Buff

幹貨分享!DevExpressv16.2最新版演示示例等你來收!

二進制 最新動態 版本升級 為解決大家找資源難的問題,EVGET聯合DevExpress控件中文網盤點熱門的DevExpress資訊、Demo示例、版本升級及下載,以及各種教程推薦等。更多下載及資訊也可以在DevExpress控件中文網中找到,及時了解最新動態>>示例Demo(仍在持續

3.2 標準庫型string

讀寫 什麽 empty lin 標準庫 urn 錯誤 序列 nbsp #include <string> #include <iostream> using std::string; using std::cin; using std::cout;

3.2 標準庫型string

logs 語句 color 使用 ring 索引 cout iostream stream #include <iostream> #include <string> using std::cin; using std::cout; using

Hadoop作業性能指標及數調優實例 Hadoop作業性能調優7個建議

optimize 自帶 管理 導致 10g avg merge map 設置 作者:Shu, Alison Hadoop作業性能調優的兩種場景: 一、用戶觀察到作業性能差,主動尋求幫助。 (一)eBayEagle作業性能分析器 1. Hadoop作業性能異常指標 2.

10.2-全棧Java筆記:最全面的IO技術

java上節我們聊到「IO技術概念及入門」這節我們繼續聊一下IO技術的分類。Java中流的概念細分按流的方向分類:輸入流:數據流向是數據源到程序(InputStream、Reader結尾的流)輸出流:數據流向是程序到目的地(OutPutStream、Writer結尾的流)按處理的數據單元:字節流:按照字節讀取

布爾操作符別名C++函數動態內存分配newdelete引用day02

color 返回 void double 強制 也會 了解 關系 指針 六 C++的布爾類型 1 bool類型是C++中基本類型,專門表示邏輯值:true/false 2 bool在內存上占一個字節:1表示true,0表示false 3 bool類型可以接收任意類型和表達

基於樹莓派Raspberry Pi平臺的MQ-2煙霧報警系統以及結合Zabbix監控的實現

Raspberry Pi Zabbix和嵌入式系統的結合 Python3 樹莓派和MQ-2氣體檢測 一、前期準備 達成目標:   利用Rapberry Pi 驅動MQ-2煙霧報警模塊,對信息進行采集和提取,而後Zabbix監控系統來收集和處理信息采集到的信息。

[python]My Unique JsonDiff演算法——如何計算2個json串之間的差距並Diff出來:編輯距離Levenshtein演算法

    啊啊,年底忙著簽證什麼的,好久沒寫日誌啦。。。。新年到來,整點乾貨出來給大家~~順便為自己考試和申請學校攢點人品~~     之前實習的時候,因為實習公司的業務需求,需要一個比對json字串差異的演算法,然而我在網上查了很久的資料,發現竟然沒有現成

javaSE之面向物件程式設計->與物件——1 and 2

一、面向物件程式設計的簡介 在C語言的學習中我們所有的程式風格都是面向過程的,也就是比如兩個數相加這個程式段需要多次執行那麼我們在C語言中只能通過程式碼的賦值貼上才可以辦到,但是我們在面向過程程式設計裡面也有這樣類似的思想,就是函式。在java中我們採用面向物件的方法,就是可以將程式碼的可重

0 httpd2.2配置詳解-Apache配置文件詳解-

切換 more 簡化 css 程序 ip地址 在服務器 filter utf httpd-2.2 15 curl命令 curl是基於URL語法在命令行方式下工作的文件傳輸工具,它支持FTP, FTPS, HTTP, HTTPS, GOPHER,

深入理解計算機系統2.8---浮點數的舍入,Java中的舍入例子以及浮點數運算重要

https://www.cnblogs.com/zuoxiaolong/p/computer12.html 前言     上一章我們簡單介紹了IEEE浮點標準,本次我們主要講解一下浮點運算舍入的問題,以及簡單的介紹浮點數的運算。   之前我們已經提到過,有很多小數是二進位制