即使走的再遠(yuǎn),也勿忘啟程時的初心
C/C++ 游戲開發(fā)
Hello,米娜桑們,這里是君兮_,我之前看過一套書叫做《明朝那些事兒》,把本來枯燥的歷史講的生動有趣。而C++作為一門接近底層的語言,無疑是抽象且難度頗深的。我希望能努力把抽象繁多的知識講的生動又通俗易懂,因此,咱們這個講解C++的系列博客就叫做《C++那些事兒》啦,而今天我們要講的內(nèi)容是C++中的函數(shù)重載與引用
-
好了廢話不多說,開始我們今天的學(xué)習(xí)吧??!
函數(shù)重載
- 說到函數(shù)重載,很多人不理解重載是什么意思,其實(shí)它就在我們身邊,我來舉個例子:
一天,你的舍友有節(jié)課沒去上課,但是碰巧老師上課點(diǎn)名點(diǎn)到他了,老師就問你:他來了嗎?
你回答說:如來
老師又問你:到底來沒來?
你回答說:如來
于是老師就把你請出教室了
- 自然語言中,一個詞可以有多重含義,人們可以通過上下文來判斷該詞真實(shí)的含義,即該詞被重載了
- 那在C++中什么是函數(shù)重載呢?
函數(shù)重載的概念
- 函數(shù)重載:是函數(shù)的一種特殊情況,C++允許在同一作用域中聲明幾個功能類似的同名函數(shù),這
些同名函數(shù)的形參列表(參數(shù)個數(shù) 或 類型 或 類型順序)不同,常用來處理實(shí)現(xiàn)功能類似數(shù)據(jù)類型
不同的問題
#include<iostream>
using namespace std;
// 1、參數(shù)類型不同
int Add(int x, int y)
{
cout << "int類型的Add" <<" "<< x + y << endl;
return x + y;
}
double Add(double x, double y)
{
cout << "double類型的Add" << " " << x + y << endl;
return x + y;
}
// 2、參數(shù)個數(shù)不同
void f()
{
cout << "f()" << endl;
}
void f(int a)
{
cout << "f(int a)" << endl;
}
// 3、參數(shù)類型順序不同
void f(int a, char b)
{
cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{
cout << "f(char b, int a)" << endl;
}
int main()
{
int x = 0;
int y = 0;
Add(1, 5);
f();
f(10);
f(10, 'b');
f('a', 10);
return 0;
}
- 了解了函數(shù)重載的概念和基本使用方法后,很多人可能會想,為什么C++支持函數(shù)重載而C不支持函數(shù)重載呢?下面我們來討論一下這個問題
C++支持函數(shù)重載的原理–名字修飾(name Mangling)
- 在C/C++中,一個程序要運(yùn)行起來,需要經(jīng)歷以下幾個階段:預(yù)處理、編譯、匯編、鏈接。
- 這里對于沒有接觸過匯編語言以及編譯鏈接的同學(xué)來說非常復(fù)雜,也不是我?guī)拙湓捑湍苷f清楚的,因此大家簡單理解記住結(jié)論即可,我也不會講太深,隨著之后我們C++之旅的進(jìn)程,當(dāng)我們接觸到更多有關(guān)內(nèi)容后,我再在合適的地方具體解釋。
- 這張圖片大概展示了在編譯鏈接階段各階段進(jìn)行的操作
- 由于Windows下vs的修飾規(guī)則過于復(fù)雜,而Linux下g++的修飾規(guī)則簡單易懂,我們通過在linux下編譯后生成的匯編來講解這部分內(nèi)容
-
Linux環(huán)境下采用C語言編譯器編譯后結(jié)果
- 結(jié)論:在linux下,采用gcc編譯完成后,函數(shù)名字的修飾沒有發(fā)生改變
-
采用C++編譯器編譯后結(jié)果
- 結(jié)論:在linux下,采用g++編譯完成后,函數(shù)名字的修飾發(fā)生改變,編譯器將函數(shù)參數(shù)類型信息添加到修改后的名字中
最終結(jié)論(在目前學(xué)習(xí)階段記住這個結(jié)論就行)
1.C語言之所以沒辦法支持重載,是因?yàn)橥瘮?shù)沒辦法區(qū)分。而C++是通過函數(shù)修飾規(guī)則來區(qū)分,只要參數(shù)不同,修飾出來的名字就不一樣,就支持了重載。
2. 如果兩個函數(shù)函數(shù)名和參數(shù)是一樣的,返回值不同是不構(gòu)成重載的,因?yàn)檎{(diào)用時編譯器沒辦法區(qū)分。
引用
1.引用概念
- 引用不是新定義一個變量,而是給已存在變量取了一個別名,編譯器不會為引用變量開辟內(nèi)存空間,它和它引用的變量共用同一塊內(nèi)存空間
- 在C++中,引用的作用類似于指針,但是它不開辟空間,在很多情況下,引用是比使用指針更好的選擇。
- 至于起別名,引用就相當(dāng)于這個變量的外號一樣
比如 孫悟空,如果你是唐僧,你可以叫他悟空
如果你是豬八戒或者沙僧,你可以叫他大師兄
如果你是某地界的土地神,你可以叫他孫大圣
如果你是他的死對頭,你可以叫他潑猴或者弼馬溫… -
上述的這些,都是孫悟空的"引用:,也就是別名
類型& 引用變量名(對象名) = 引用實(shí)體;
void Test()
{
int a = 10;
int& ra = a;//<====定義引用類型
printf("%p\n", &a);
printf("%p\n", &ra);
}
int main()
{
Test();
}
-
引用與原變量指向同一塊空間
-
注意:引用類型必須和引用實(shí)體是同種類型的
2.引用特性
- 1. 引用在定義時必須初始化
- 2. 一個變量可以有多個引用
- 3. 引用一旦引用一個實(shí)體,再不能引用其他實(shí)體
void Test()
{
int a = 10;
int& ra = a;//<====定義引用類型
int& b = a;//一個變量可以有多個別名
printf("%p\n", &a);
printf("%p\n", &ra);
printf("%p\n", &b);
}
- 多個引用仍然指向同一塊空間
- 必須初始化,不然會報(bào)錯
3.常引用
void TestConstRef()
{
const int a = 10;
//int& ra = a; // 該語句編譯時會出錯,a為常量
const int& ra = a;
}
- 最常見的一種常引用,我們知道引用作為變量的別名,當(dāng)改變引用的值時,是會改變變量的值的,因此當(dāng)變量被const修飾時,它的引用也必須用const修飾
void TestConstRef()
{
// int& b = 10; // 該語句編譯時會出錯,b為常量
const int& b = 10;
double d = 12.34;
//int& rd = d; // 該語句編譯時會出錯,類型不同
const int& rd = d;
}
- 當(dāng)我們直接吧一個常量給一個引用時,必須加const,原因與第一種情況相同,而常量就更不可能讓你通過引用來修改它的值了
void TestConstRef()
{
double d = 12.34;
//int& rd = d; // 該語句編譯時會出錯,類型不同
const int& rd = d;
}
- 這里是存在一個類型的隱式轉(zhuǎn)換的,把double類型的轉(zhuǎn)換成int型,這里類型發(fā)生了轉(zhuǎn)換,因此我們也不能通過別名來修改變量,因此必須加const
4.引用的使用場景
(1).做函數(shù)的參數(shù)
void Swap(int& left, int& right)
{
int temp = left;
left = right;
right = temp;
}
- 和指針在這里的使用方法是類似的,就不過多展開了
(2).做返回值
int& Count()
{
static int n = 0;
n++;
// ...
return n;
}
注意:如果函數(shù)返回時,出了函數(shù)作用域,如果返回對象還在(還沒還給系統(tǒng)),則可以使用引用返回,如果已經(jīng)還給系統(tǒng)了,則必須使用傳值返回。
- 下面我們來看一個例子
int& Add(int a, int b)
{
int c = a + b;
return c;
}
int main()
{
int& ret = Add(1, 2);
Add(3, 4);
cout << "Add(1, 2) is :"<< ret <<endl;
return 0;
}
- 因此,當(dāng)我們運(yùn)行時出現(xiàn)這種結(jié)果,也就不奇怪了
- 那應(yīng)該怎么解決上述的這種問題呢?
- 很簡單,我們讓函數(shù)解釋時,不會釋放申請的空間就好了
int& Add(int a, int b)
{
static int c = a + b;
return c;
}
int main()
{
int& ret = Add(1, 2);
Add(3, 4);
cout << "Add(1, 2) is :" << ret << endl;
return 0;
}
傳值與傳引用效率比較
- 以值作為參數(shù)或者返回值類型,在傳參和返回期間,函數(shù)不會直接傳遞實(shí)參或者將變量本身直接返回,而是傳遞實(shí)參或者返回變量的一份臨時的拷貝,因此用值作為參數(shù)或者返回值類型,效率是非常低下的,尤其是當(dāng)參數(shù)或者返回值類型非常大時,效率就更低。
- 總的來說,你在這里可以暫時把引用類比成指針來使用,等之后學(xué)習(xí)了類和對象之后,才能更加明白引用在使用時候的妙處
引用和指針的區(qū)別
- 在語法概念上引用就是一個別名,沒有獨(dú)立空間,和其引用實(shí)體共用同一塊空間。
- 在底層實(shí)現(xiàn)上實(shí)際是有空間的,因?yàn)橐檬前凑罩羔樂绞絹韺?shí)現(xiàn)的。
int main()
{
//int& ret = Add(1, 2);
char c = 'a';
char& rc = c;
char* rrc = &c;
cout << "&rc"<<" "<< sizeof(c) << endl;
cout << "rrc" <<" "<< sizeof(rrc) << endl;
return 0;
}
- 在這里編譯器告訴我們引用占一個字節(jié),而指針占8個字節(jié),可事實(shí)真的如此嗎?
-
通過底層的匯編代碼,我們可以知道,實(shí)際上,引用是按指針方式實(shí)現(xiàn)的是占空間的,至于為什么編譯器告訴你它不占空間,因?yàn)樵贑++規(guī)定時說引用是一個別名是不占空間的,它總不能自己打自己臉呀
引用與指針的其他區(qū)別點(diǎn)
1. 引用概念上定義一個變量的別名,指針存儲一個變量地址。
2. 引用在定義時必須初始化,指針沒有要求
3. 引用在初始化時引用一個實(shí)體后,就不能再引用其他實(shí)體,而指針可以在任何時候指向任何
一個同類型實(shí)體
4. 沒有NULL引用,但有NULL指針
5. 在sizeof中含義不同:引用結(jié)果為引用類型的大小,但指針始終是地址空間所占字節(jié)個數(shù)(32
位平臺下占4個字節(jié))
6. 引用自加即引用的實(shí)體增加1,指針自加即指針向后偏移一個類型的大小
7. 有多級指針,但是沒有多級引用
8. 訪問實(shí)體方式不同,指針需要顯式解引用,引用編譯器自己處理
9. 引用比指針使用起來相對更安全
總結(jié)
-
好啦,我們今天的內(nèi)容就先到這里啦!今天講解了函數(shù)重載與引用使用方法以及有關(guān)它們使用的細(xì)節(jié)和注意事項(xiàng),這兩塊的知識點(diǎn)會一直伴隨你C++學(xué)習(xí)之路,是非常重要的,因此希望大家把有關(guān)的重點(diǎn)和難點(diǎn)多看幾遍加深理解。
-
有任何的問題和對文章內(nèi)容的疑惑歡迎在評論區(qū)中提出,當(dāng)然也可以私信我,我會在第一時間回復(fù)的??!
新人博主創(chuàng)作不易,如果感覺文章內(nèi)容對你有所幫助的話不妨三連一下再走唄。你們的支持就是我更新的動力?。?!
**(可莉請求你們?nèi)B支持一下博主?。。↑c(diǎn)擊下方評論點(diǎn)贊收藏幫幫可莉吧)** 文章來源:http://www.zghlxwxcb.cn/news/detail-713989.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-713989.html
到了這里,關(guān)于【C++那些事兒】函數(shù)重載與C++中的“指針“——引用的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!