函數重載:
函數重載定義:
函數重載:是函數的一種特殊情況,C++允許在 同一作用域 中聲明幾個功能類似的 同名函數,這些 同名函數的形參清單(參數個數 或 類型 或 順序)必須不同,常用來處理實作功能類似資料類型不同的問題。
舉個栗子:
#include<iostream>
#include<stdlib.h>
using namespace std;
int ADD(int a,int b)
{
int c;
c=a+b;
return c;
}
int ADD(int a,int b,int c)
{
int d;
d=a+b+c;
return d;
}
int main()
{
int ret1,ret2;
ret1=ADD(1,2);
ret2=ADD(1,2,3);
printf("%d\n",ret1);
printf("%d\n",ret2);
system("pause");
return 0;
}
這就是一個函數重載,兩個同名的ADD函數,功能是做加法,第一個有兩個參數,求兩個數字的和。而第二個有三個參數,求三個數字之和。因為他們滿足,在同一作用域中,同名的函數,但參數個數卻不同,是以構成函數重載。
看一下結果驗證一下。
而且無法重載僅按傳回值類型區分的函數。
這裡可能會有一個誤區:
#include<iostream>
#include<stdlib.h>
using namespace std;
short Add(short left, short right)
{
return left+right;
}
short Add( short right,short left)
{
return left+right;
}
int main()
{
short ret1,ret2;
printf("%d %d",ret1,ret2);
system("pause");
return 0;
}
會有人問,函數參數的順序不是不一樣嗎?為什麼不構成重載?
原因,構成函數重載的條件是,一:參數個數不同 、二:參數類型不同、三:形參順序不同。可以看到因為參數的類型相同了,是以不能構成重載。
可以看到當參數類型不同時,就可以構成重載,而參數的順序不同之前還要考慮參數的類型不能相同。
總結為:
1.當函數參數個數不同即構成重載。
2.當參數類型不同時,就可構成重載。
3.當參數的順序不同,且參數的類型也不能相同,才能構成重載。
引用:
引用不是新定義一個變量,而是給已存在變量取了一個别名,編譯器不會為引用變量開辟記憶體空間,它和它引用的變量共用同一塊記憶體空間。
比如:你在家的時候,你媽媽可能會叫你“王大錘”,而你的同學叫你“老王”,而你的真名可能叫王小萌。雖然你有這麼多名字,但你家戶口本也就隻有一個你的名字,國家是不會給你多弄一張身份證的。
具體如何引用呢?
類型& 引用變量名(對象名) = 引用實體
驗證:
#include<iostream>
#include<stdlib.h>
using namespace std;
void Test()
{
int a=10;
int& A=a;//引用
printf("%d\n",a);
printf("%d\n",A);
printf("%p\n",&a);//%p列印位址
printf("%p\n",&A);
}
int main()
{
Test();
system("pause");
return 0;
}
可以看到A的值也是10,并且通過列印這兩個變量,可以發現這兩個變量位址相同,a和A共用一塊記憶體空間。
注意:引用類型必須和引用實體是同種類型的。
引用特性:
- 引用在定義時必須初始化
- 一個變量可以有多個引用
- 引用一旦引用一個實體,再不能引用其他實
具體執行個體看代碼:
#include<iostream>
#include<stdlib.h>
using namespace std;
void test()
{
int a=3;
int b=6;
int& A=a;//初始化
//int& A;//報錯顯示 引用變量"A"需要初始值設定項
int& ra=a;//可以有多個引用
int& A=b;//這裡會報錯
printf("%d %d %d %d",a,b,A,ra);
}
int main()
{
test();
system("pause");
return 0;
}
看一下運作結果
先看一下報錯的部分:由此可見,引用一旦引用一個實體,再不能引用其他實體。
修改後:
常引用
注意的一些問題:
void test1()
{
const int a=10;
//int& A=a;//這裡會報錯,顯示:将"int &"類型的引用
//綁定到"const int"類型的初始值設定項時,限定符被丢棄。
//這裡涉及到const常量和普通的常量之間的調用關系。
//解決方法是
const int& A=a;
//int& b=1;//這裡報錯,非常量引用的初始值必須為左值,即b不能為常量。
double b=1.2;
//int& B=b;//報錯,類型不同無法引用
double& B=b;
const int& rb=b;
}
應用場景:
1.做參數
我們都知道,如果要交換兩個變量的内容在傳參時,需要傳位址過去,而且需要解引用才能交換兩個變量的值。如:
void test2(int*left,int*right)
{
int temp=*left;
*left=*right;
*right=temp;
}
int main()
{
int left=1;
int right=2;
test2(&left,&right);
cout<<left<<" "<<right<<endl;
system("pause");
return 0;
}
但如果用變量的引用做參數,就會很好的解決這個問題,不用傳位址過去,因為引用和實體所占得是同一塊記憶體空間。
void test2(int& left,int& right)
{
int temp=left;
left=right;
right=temp;
}
int main()
{
int left=1;
int right=2;
test2(left,right);
cout<<left<<" "<<right<<endl;
system("pause");
return 0;
}
運作結果如下:
2.做傳回值
先看一段代碼:
#include<iostream>
#include<stdlib.h>
using namespace std;
int Add(int a,int b)
{
int c;
c=a+b;
return c;
}
int main()
{
int ret=Add(12,23);
Add(23,24);
cout<<ret<<endl;
system("pause");
return 0;
}
這是一個簡單的求和函數,當引用用作函數傳回值會發生什麼呢?
猜一下下面代碼的列印結果:
int& Add(int a,int b)
{
int c;
c=a+b;
return c;
}
int main()
{
int& ret=Add(12,23);
Add(23,24);
cout<<ret<<endl;
system("pause");
return 0;
}
可以看到,列印結果是47,也就是說列印的是Add(23,24)這個的和,這是為什麼呢?
再加一個求和:
這是因為:
如果函數傳回時,離開函數作用域後,其棧上空間已經還給系統,是以不能用棧上的空間作為引用類型 傳回。如果以引用類型傳回,傳回值的生命周期必須不受函數的限制(即比函數生命周期長)
也就是int & ret 不再受Add(12,23)的限制了,這個傳回值的生命周期比函數的生命周期還要長,是以每次調用這個函數,它的傳回值都一直還在。
傳值、傳引用效率比較:
以值作為參數或者傳回值類型,在傳參和傳回期間,函數不會直接傳遞實參或者将變量本身直接傳回,而是傳遞實 參或者傳回變量的一份臨時的拷貝,是以用值作為參數或者傳回值類型,效率是非常低下的,尤其是當參數或者傳回 值類型非常大時,效率就更低
寫段代碼測試一下:
#include <time.h>
#include<iostream>
#include<stdlib.h>
using namespace std;
struct A
{
int a[10000];
};
void TestFunc1(A a)
{}
void TestFunc2(A& a)
{}
void TestRefAndValue() {
A a;
// 以值作為函數參數
size_t begin1 = clock();
for (size_t i = 0; i < 10000; ++i)
TestFunc1(a);
size_t end1 = clock();
// 以引用作為函數參數
size_t begin2 = clock();
for (size_t i = 0; i < 10000; ++i)
TestFunc2(a);
size_t end2 = clock();// 分别計算兩個函數運作結束後的時間
//值和引用的作為傳回值類型的性能比較
cout << "以值作為函數參數time:"<< end1 - begin1 << endl;
cout << "以引用作為函數參數time:" << end2 - begin2 << endl;
}
// 運作多次,檢測值和引用在傳參方面的效率差別
int main()
{
for (int i = 0; i < 10; ++i)
{
TestRefAndValue();
}
system("pause");
return 0;
}
運作結果如下:
很明顯可以看到以引用作為函數參數效率會比較高。
另外,以引用作為傳回值也是一樣,引用的效率高。
傳值和指針在作為傳參以及傳回值類型上效率相差很大
引用和指針的差別:
雖然說引用隻是一個别名,指向的是同一塊的記憶體空間,概念上引用是沒有獨立空間的,但是在底層實作上實際是有空間的,因為引用是按照指針方式來實作的
而他們有差別嗎?
1.引用在定義時必須初始化,指針沒有要求
2. 引用在初始化時引用一個實體後,就不能再引用其他實體,而指針可以在任何時候指向任何一個同類型實 體
3. 沒有NULL引用,但有NULL指針
4. 在sizeof中含義不同:引用結果為引用類型的大小,但指針始終是位址空間所占位元組個數(32位平台下占4 個位元組)
5. 引用自加即引用的實體增加1,指針自加即指針向後偏移一個類型的大小
6. 有多級指針,但是沒有多級引用
7. 通路實體方式不同,指針需要顯式解引用,引用編譯器自己處理
8. 引用比指針使用起來相對更安全
内聯函數(了解即可)
定義:
以inline修飾的函數叫做内聯函數,編譯時C++編譯器會在調用内聯函數的地方展開,沒有函數壓棧的開銷, 内聯函數提升程式運作的效率
特性:
1. inline是一種以空間換時間的做法,省去調用函數額開銷。是以代碼很長或者有循環/遞歸的函數不适宜使 用作為内聯函數。
2. inline對于編譯器而言隻是一個建議,編譯器會自動優化,如果定義為inline的函數體内有循環/遞歸等 等,編譯器優化時會忽略掉内聯。
3. inline不建議聲明和定義分離,分離會導緻連結錯誤。因為inline被展開,就沒有函數位址了,連結就會找不到