本篇文章將整理出關於引數預設和引用的一些知識。
(一)引數預設:
引數預設包括全預設和半預設。顧名思義,全預設就是函式的所有引數都給出預設值,半
預設就是僅有函式的部分引數給出了預設值。
看下邊的一段**:
#includeusing namespace std;
int add(int x, int y)
int main()
要是寫出上邊的一段**,低版本的vs會編譯不通過,報錯是add函式不
接收0個引數,
高版本vs會有紅色標註。要是對於函式呼叫的時候不想給出引數,我們可以使用預設參
數,若將add函式寫成這樣就好了:
int add(int x = 0, int y = 0)
這就是所謂的全預設。那麼半預設呢??繼續例項:
int add(int x , int y = 0)
int main()
這樣子的話,最後會得到10和0相加。當然呼叫的時候,我們也可以給出兩個引數。如果
我們將x給出缺省,y不預設,看可以不??
int add(int x = 0 , int y)
要是add函式寫成上邊這樣,高版本vs編譯器會紅線報錯:預設引數不在引數列表末尾。
想想這是為什麼?其實,想一下就明白了,呼叫的時候(當然實參是只有乙個)會把給
出的實參賦值給函式引數列表的第乙個形參,肯定就不對了嘛。要是用更專業的說法解
釋,本人認為:
函式引數入棧的時候是實參進入add
函式的棧幀,直接就當作第乙個引數,所以~
總結:使用半預設,預設的引數只能在引數列表的最後邊。
預設引數的用途:假如要傳性別這個引數給函式,我們又約定預設為男,所以,只需要
在需要傳的性別是女時,給出引數。這就是預設引數的用途。
(二)引用
引用就是給乙個變數起乙個別名。
比如:
int a = 10;
int &ra = a;//ra是a的別名
int &refa = a;//refa也是a的別名
總結:乙個變數可以有多個別名。
定義引用的時候必須初始化(指明定義的引用是哪個變數的別名)。
引用只能在初始化的時候引用一次。
既然說,乙個變數可以有多個別名,改變了別名的值,也就改變了變數的值,是不是感
覺引用就很不安全了??
其實並不是,如果不想改變,可以使用const修飾。
int a= 10;
const int &ra = a;
ra = 20;//報錯!
關於const,在c中const修飾的變數是常變數,既有常量的屬性,也有變數的屬性。在c
++中,const修飾的變數就是常量。不可修改。
在學習指標的時候,如果乙個函式的功能僅僅是列印或者是某個引數不可以被改變的時
候,我們可以用const修飾。在使用引用的時候也是一樣的。
舉例:
void print_a(const int &ra)
int main()
在cpp中,如果const修飾的是區域性變數,則該區域性變數是在棧裡。不是不可以修改,可
以使用指標修改。
如果const修飾的是全域性變數,不使用的時候是不會被分配空間的(&n是錯誤的),只有
在使用的時候也是有位址的。
const int n = 10;
int main()
;//這裡並不算使用n,此時的n仍相當於巨集識別符號
const int *p = &n;//n才有空間,並且是唯讀區,不可修改的。
system("pause");
return 0;
}
關於const引用的正確使用:看下邊的幾段**:
const int n = 10;
int &refn = a;
此時 refa是可以改變的,進而n的值可以改變。這就不對了嘛。(n是不可以改變的)。
使得n從安全變成不安全。
int m = 10;
const int &refm = m;
這個就是正確的。使得m從不安全變得安全。
const int &refd= 5;
這個是正確的。const修飾的refd是乙個常量的引用。
double d = 6.15;
int &refd = d;
這個是不對的。要是這樣就對了:
double d = 6.15;
const int &refd = d;
為什麼呢??由於引用的型別是int,變數的型別是double,所以此時就會用double型別
的d建立乙個臨時變數(也是d的隱式型別轉換),refd引用的是臨時變數。確切的說就
是臨時常量。此時refd =6
refd和d不在乙個空間。
引用作為函式引數:
這裡需要宣告:引用的底層仍然是指標(這個可以通過彙編**觀到)。
下邊我們來測試傳引用和傳值得效率問題:
#include#includeusing namespace std;
struct bigdata
;int getdata(bigdata bd)
int main()
; int i = 0;
int start = gettickcount();
for (i = 0;i < 100000000;i++)
int end = gettickcount();
cout << end - start << endl;
system("pause");
return 0;
}
**測試出的結果是6000毫秒左右。注意:每次執行的結果都不大一樣,這根cpu的狀態
有關。當把上邊**改為傳引用:效率可以提高大約一半,自己可以嘗試。
引用作為函式的返回值:
看**:
int& fun()
int main()
上邊這段**確實可以輸出10.不過要是把上邊的**做以修改:
int& fun()
int main()
看上邊的**,在高版本的vs下輸出:
楊先生你好10
在低版本環境下ret的值會被改變。因為ret接收的是區域性變數num,兩者占用同乙個空間
當num消失了,ret也就消失了,變成隨機值。
高版本vs(比如vs2015)為什麼ret的值一直是10,不知道做了什麼優化。。
如果將上邊的**做以修改:
int& fun()
int main()
這個ret的值不會改變。看原理:
後者的ret就不是引用了,儲存的僅僅是num的值,所以不會隨著num的消失而消失。
當引用作為函式的返回值的時候,有時會提高效率,有時並不會~~
我們知道,當函式的返回值,int或者double等等內建型別時,返回值是用暫存器帶回
的。然而最大的暫存器也就32位,要是我們要返回乙個比較大的結構體時,會使用引用
,引用不會建立臨時變數,直接把需要帶回的值賦值給接收返回值的變數。
總結:用函式的返回值的型別不是內建型別時,使用引用返回,會提高效率(減少創
建臨時物件)。
當返回的是內建型別時,會用暫存器帶回,跟使用引用返回的效率差不多。
引用和指標的區別:
1.指標在定義的時候可以不初始化,但是引用不行。
2.引用只能引用乙個變數,而一般的指標變數並不是(除了const修飾的指標)
3.指標的大小僅與品台有關,而引用的大小與引用的物件的型別有關。
4.指標自加時,使得指標指向當前指向空間的下乙個空間;引用自加時,會使自身和它
所引用的物件的值加1.
5.引用比指標更安全。(使用指標時,一定要檢查指標的值是否是null)
越努力,越幸運~~
03 bool,const,引用,預設引數
一 bool bool val true vs中佔1位元組,記憶體中數值為0x01 val false 記憶體中數值為0x00 val 100 記憶體中數值為0x01,warning c4305 從 int 到 bool 截斷 val 1 記憶體中數值為0x01,warning c4305 從 in...
C 中的預設引數 引用 函式過載
我們學過c語言的都知道,在函式沒有指定指定引數列表時,預設可以接受任意多個引數,便有了可變引數列表。在c 中,對於引數列表有了嚴格的檢測,對於沒有引數列表的函式,預設為void,不允許接受任何引數。那麼預設引數又是什麼呢?下面我們通過乙個例子來說明。include using namespace s...
python 預設引數 Python預設引數有坑?
最近有小夥伴在面試中遇到了 關於函式預設引數的坑 的題目,少數夥伴對此問題理得不是太清楚,今天匯智妹請到匯智動力高階教師鄧老師為大家詳細講解一下,幫助不太清楚的小夥伴清晰的梳理一遍。鄧老師本次主要從以下三點來講解 什麼是預設引數?函式預設引數的坑是什麼?函式預設引數為什麼會有坑?一 什麼是預設引數 ...