一、缺省參數(shù)
1.1 定義
?缺省參數(shù)是聲明或定義函數(shù)時(shí)為函數(shù)的參數(shù)指定一個(gè)缺省值。在調(diào)用該函數(shù)時(shí),如果沒(méi)有指定實(shí)參則采用該形參的缺省值,否則使用指定的實(shí)參。
//缺省參數(shù)
void fun(int a = 10)
{
cout << a << endl;
}
int main()
{
fun(2);//傳參了,使用顯式傳遞的值
fun();//沒(méi)有傳參,使用缺省參數(shù)
}
?上面代碼在fun
函數(shù)的形參部分給了缺省值10,這意味著在調(diào)用fun
函數(shù)的時(shí)候可以傳參,也可以不傳參,如果傳參了那形參a
就使用顯式傳的值,如果沒(méi)有傳參那形參a
就使用缺省值10。
1.2 缺省參數(shù)分類(lèi)
- 全缺省參數(shù)
void text(int a = 5, int b = 15, int c = 25)//全缺省,所有參數(shù)都給了缺省值
{
cout << a << ' ';
cout << b << ' ';
cout << c << ' ';
cout << endl;
}
int main()
{
text(1, 2, 3);
text(1, 2);
text(1);
text();
return 0;
}
?對(duì)于全缺省參數(shù)在傳參的時(shí)候,參數(shù)是按照從左往右的順序進(jìn)行缺省的,不能跳著缺省,即:讓第一個(gè)形參和第三個(gè)形參都使用顯式傳遞值,而讓第二個(gè)參數(shù)使用缺省值,這種做法是不被允許的。以上的代碼為例:當(dāng)一個(gè)參數(shù)也沒(méi)傳的時(shí)候,形參全部使用缺省值;只傳一個(gè)參數(shù)的時(shí)候,這個(gè)參數(shù)會(huì)賦值給第一個(gè)形參,后面兩個(gè)形參使用缺省值;傳兩個(gè)參數(shù)的時(shí)候,會(huì)把第一個(gè)實(shí)參賦值給第一個(gè)形參,把第二個(gè)實(shí)參賦值給第二個(gè)形參,最后一個(gè)形參使用缺省值;傳三個(gè)參數(shù)的時(shí)候,所有形參都是用實(shí)參傳過(guò)來(lái)的值。這里要與參數(shù)壓棧區(qū)分,參數(shù)壓入棧楨的順序是從右往左。
- 半缺省參數(shù)
void text(int a, int b = 15, int c = 25)//半缺省,只有部分參數(shù)給了缺省值
{
cout << a << ' ';
cout << b << ' ';
cout << c << ' ';
cout << endl;
}
int main()
{
text(1, 2, 3);
text(1, 2);
text(1);
return 0;
}
注意:
?半缺省參數(shù)必須從右往左依次給缺省值,即:第一個(gè)形參和第二個(gè)形參給了缺省值,而第三個(gè)形參沒(méi)有給缺省值,這種情況是不被允許的。也不能隔著給,即:第三個(gè)形參和第一個(gè)形參給了缺省值,而第二個(gè)形參沒(méi)有給缺省值,這種情況也是不被允許的。
1.3 缺省參數(shù)只能出現(xiàn)在函數(shù)聲明中
?為了避免出現(xiàn)不一致的情況,要求缺省參數(shù)不能在函數(shù)聲明和定義中同時(shí)出現(xiàn),并且只能出現(xiàn)在函數(shù)的聲明中。為什么不能只出現(xiàn)在函數(shù)的定義中?
?因?yàn)樵陬A(yù)處理階段會(huì)把頭文件展開(kāi),一般函數(shù)的聲明就放在頭文件中。如果只在函數(shù)的定義中給了缺省值,那頭文件展開(kāi)后,函數(shù)的聲明語(yǔ)句中并沒(méi)有缺省參數(shù),此時(shí)如果在調(diào)用該函數(shù)的時(shí)候沒(méi)有傳參希望使用它的缺省值,那在程序編譯的過(guò)程中就會(huì)出現(xiàn)問(wèn)題,即:函數(shù)的聲明沒(méi)給出缺省值,意味著需要顯式傳參,但在調(diào)用該函數(shù)的時(shí)候卻沒(méi)有傳參。
二、函數(shù)重載
?在自然語(yǔ)言中,一個(gè)詞可以有多重含義,人們可以通過(guò)上下文來(lái)判斷該詞真實(shí)的含義,即該詞被重載了。比如:有人說(shuō),我們國(guó)家有兩個(gè)體育項(xiàng)目大家根本不用看,也不用擔(dān)心。一個(gè)是乒乓球,一個(gè)是男足。前者是“誰(shuí)也贏不了!”,后者是“誰(shuí)也贏不了!”但是大家懂的都懂,前者意思是誰(shuí)都贏不了我們,而后者的意思是我們贏不了別人。
2.1 定義
?函數(shù)重載是函數(shù)的一種特殊情況,C++允許在同一作用域中聲明幾個(gè)功能類(lèi)似的同名函數(shù),這些同名函數(shù)的形參列表(參數(shù)個(gè)數(shù)或類(lèi)型或類(lèi)型順序)不同,常用來(lái)處理實(shí)現(xiàn)功能類(lèi)似數(shù)據(jù)類(lèi)型不同的問(wèn)題。
2.2 構(gòu)成重載的幾種情況
- 參數(shù)類(lèi)型不同:
int Add(int left, int right)
{
cout << "int Add(int left, int right)" << endl;
return left + right;
}
double Add(double left, double right)
{
cout << "double Add(double left, double right)" << endl;
return left + right;
}
int main()
{
cout << Add(1, 2) << endl;
cout << Add(1.0, 2.0) << endl;
}
?上面的代碼定義了兩個(gè)同名的Add
函數(shù),但是它們的參數(shù)類(lèi)型不同,第一個(gè)兩個(gè)參數(shù)都是int
型,第二個(gè)兩個(gè)參數(shù)都是double
型,在調(diào)用Add
函數(shù)的時(shí)候,編譯器會(huì)根據(jù)所傳實(shí)參的類(lèi)型自動(dòng)判斷調(diào)用哪個(gè)函數(shù)。至于編譯器為什么能這么做稍后再說(shuō)。
- 參數(shù)個(gè)數(shù)不同:
void fun()
{
cout << "f()" << endl;
}
void fun(int a)
{
cout << "f(int a)" << endl;
}
int main()
{
fun();
fun(1);
return 0;
}
- 參數(shù)類(lèi)型順序不同:
// 3、參數(shù)類(lèi)型順序不同
void Text(int a, char b)
{
cout << "Text(int a,char b)" << endl;
}
void Text(char b, int a)
{
cout << "Text(char b, int a)" << endl;
}
int main()
{
Text(1, 'a');
Text('a', 1);
return 0;
}
- 有缺省參數(shù)的情況
void fun()
{
cout << "f()" << endl;
}
void fun(int a = 10)
{
cout << "f(int a)" << endl;
}
int main()
{
//fun();//無(wú)參調(diào)用會(huì)出現(xiàn)歧義
fun(1);//調(diào)用的是第二個(gè)
return 0;
}
?上面代碼中的兩個(gè)fun
函數(shù)根據(jù)函數(shù)重載的定義他倆是構(gòu)成函數(shù)重載的,編譯可以通過(guò),因?yàn)榈谝粋€(gè)沒(méi)有參數(shù),第二個(gè)有一個(gè)整型參數(shù),屬于上面的參數(shù)個(gè)數(shù)不同的情況。但是fun
函數(shù)存在一個(gè)問(wèn)題:在無(wú)參調(diào)用的時(shí)候會(huì)產(chǎn)生歧義,因?yàn)閷?duì)兩個(gè)fun
函數(shù)來(lái)說(shuō),都可以不傳參。
注意:
?返回值的類(lèi)型與函數(shù)是否構(gòu)成重載無(wú)關(guān)。即:函數(shù)名相同,形參列表形相同,返回值不同不會(huì)構(gòu)成函數(shù)重載。
2.3 C++支持函數(shù)重載的原理
?上面說(shuō)到,編譯器會(huì)自動(dòng)根據(jù)參數(shù)的類(lèi)型去判斷應(yīng)該調(diào)用哪個(gè)函數(shù),那編譯器究竟是如何做到的呢?要回答這個(gè)問(wèn)題會(huì)涉及到一些編譯鏈接的知識(shí),遺忘的同學(xué)可以去看看我之前的文章:【C語(yǔ)言進(jìn)階】編譯鏈接。
?其實(shí)這里涉及到函數(shù)簽名的概念,函數(shù)簽名包含了一個(gè)函數(shù)的信息,包括函數(shù)名、它的參數(shù)類(lèi)型、他所在的類(lèi)和名稱(chēng)空間以及其他信息。函數(shù)簽名用于識(shí)別不同的函數(shù),就像簽名用于識(shí)別不同的人一樣,函數(shù)的名字只是函數(shù)簽名的一部分。對(duì)于函數(shù)名相同,參數(shù)列表不同的函數(shù),編譯器和鏈接器處理符號(hào)的時(shí)候,它們使用某種名稱(chēng)修飾的方法(不同的編譯器會(huì)有所不同),使得每個(gè)函數(shù)簽名對(duì)應(yīng)一個(gè)修飾后名稱(chēng)。編譯器在匯編過(guò)程中,會(huì)將函數(shù)和變量的名字進(jìn)行修飾,形成符號(hào)名,也就是說(shuō)C++的源代碼編譯后的目標(biāo)文件中所使用的符號(hào)名是相應(yīng)的函數(shù)和變量的修飾后名稱(chēng)。C++編譯器和鏈接器都使用符號(hào)來(lái)標(biāo)識(shí)和處理函數(shù)和變量,所以對(duì)于不同函數(shù)簽名的函數(shù),即使函數(shù)名相同,編譯器和鏈接器都認(rèn)為他們是不同的函數(shù)。
?由于Windows下的修飾規(guī)則過(guò)于復(fù)雜,而Linux下g++的修飾規(guī)則簡(jiǎn)單易懂,所以下面我將利用g++演示經(jīng)過(guò)修飾后的名稱(chēng)。以下面這段代碼為例:
#include <stdio.h>
int Add(int left, int right)
{
printf("int Add(int left, int right)\n");
return left + right;
}
double Add(double left, double right)
{
printf("double Add(double left, double right)\n");
return left + right;
}
int main()
{
Add(1,2);
Add(1.0,2.0);
return 0;
}
?先用g++ text.cpp -o text.out
這條指令對(duì)上面的代碼進(jìn)行編譯生成一個(gè)可執(zhí)行程序tetx.out,再用objdump -S text.out
指令查看修飾后名稱(chēng)。
?其中_Z
是固定的前綴;3
表示函數(shù)名的長(zhǎng)度;Add
就是函數(shù)名;i
是int的縮寫(xiě),兩個(gè)i表示兩個(gè)參數(shù)都是int類(lèi)型,d
是double的縮寫(xiě),兩個(gè)d表示兩個(gè)參數(shù)都是double類(lèi)型。C++就是通過(guò)函數(shù)修飾規(guī)則來(lái)區(qū)分,只要參數(shù)不同,修飾出來(lái)的名字就不一樣,就支持了重載。通過(guò)分析可以發(fā)現(xiàn),修飾后的名稱(chēng)中并不包含任何于函數(shù)返回值有關(guān)的信息,因此也驗(yàn)證了上面說(shuō)的返回值的類(lèi)型與函數(shù)是否構(gòu)成重載無(wú)關(guān)。
?再來(lái)看看C語(yǔ)言編譯器gcc的處理結(jié)果
?可以看出經(jīng)過(guò)gcc編譯后,函數(shù)名字的修飾沒(méi)有發(fā)生改變。這也就是為什么C語(yǔ)言不支持函數(shù)重載,因?yàn)橥瘮?shù)沒(méi)辦法區(qū)分。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-515122.html
?今天的分享到這里就結(jié)束啦!如果覺(jué)得文章還不錯(cuò)的話,可以三連支持一下,您的支持就是春人前進(jìn)的動(dòng)力!文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-515122.html
到了這里,關(guān)于【C++初階】C++入門(mén)——缺省參數(shù)、函數(shù)重載的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!