2020 我的C++的学习之路 第八章函数
以C++ Primer Plus為參考書籍,自身歸納知識(shí)點(diǎn),加深記憶。
第八章 函數(shù)探幽
- 1 內(nèi)聯(lián)函數(shù)
- 2 引用變量
- 2.1 創(chuàng)建引用變量
- 2.2 引用與函數(shù)參數(shù)
- 2.3 引用與結(jié)構(gòu)
- 何時(shí)使用引用參數(shù)
- 默認(rèn)參數(shù)
- 函數(shù)重載
- 函數(shù)模板
- 顯式具體化
- 實(shí)例化與具體化
- 編譯器選擇哪個(gè)函數(shù)版本
- 完全匹配和最佳匹配
- 部分排序規(guī)則
- 關(guān)鍵詞decltype(C++11)
- 后置返回類型(C++11)
1 內(nèi)聯(lián)函數(shù)
常規(guī)的函數(shù)調(diào)用使程序跳到一個(gè)地址并在結(jié)束時(shí)返回,對(duì)于內(nèi)聯(lián)函數(shù)而言,程序無需跳轉(zhuǎn)即可執(zhí)行,因此內(nèi)聯(lián)函數(shù)運(yùn)行速度比常規(guī)函數(shù)稍快,但代價(jià)是占用更多內(nèi)存。倘若程序在10個(gè)不同的地方調(diào)用同一個(gè)內(nèi)聯(lián)函數(shù),該程序則包含該函數(shù)代碼的10個(gè)副本。
要使用內(nèi)聯(lián)函數(shù),必須采取下述措施之一:
① 函數(shù)聲明前加關(guān)鍵字inline
②函數(shù)定義前加關(guān)鍵字inline
通常的做法是省略原型,將函數(shù)頭以及函數(shù)代碼放在本應(yīng)提供原型的地方。
內(nèi)聯(lián)函數(shù)與宏
C語言使用預(yù)處理器語句#define提供宏
#define SQUARE(X) X*X
本身并不是通過傳遞參數(shù)實(shí)現(xiàn),而是通過文本替換實(shí)現(xiàn):
a = SQUARE(5.0); 其實(shí)就是a=5.0 * 5.0;
b=SQUARE(4.5+1.5)::::其實(shí)就是b=4.5+1.5 * 4.5+1.5
SQUARE(c++):::::(c++) * (c++)不同編譯器給出的結(jié)果還不一樣
內(nèi)聯(lián)函數(shù)通過傳遞參數(shù)實(shí)現(xiàn),因此在square(c++)中,傳遞c給square()函數(shù)然后再c++,在編譯器上沒有沖突存在。
2 引用變量
引用變量是C++新增的復(fù)合類型,引用是已定義變量的別名,通過將引用變量做參數(shù),函數(shù)使用原始數(shù)據(jù),而不是副本。
2.1 創(chuàng)建引用變量
int count; int &cnt = count;//int&指的是指向int的引用,count與cnt指向相同的值和內(nèi)存單元上述例子中,倘若對(duì)cnt做遞增運(yùn)算,那么count也會(huì)做相應(yīng)的變化。
int count; int &cnt; cnt = count;//引用不同于指針,必須在聲明時(shí)就用初始化該引用。2.2 引用與函數(shù)參數(shù)
#include<iostream> void swapr(int &a,int &b); void swapp(int *a,int *b); void swapv(int a,int b);int main() {using namespace std;int wallet1 = 300;int wallet2 = 350;swapr(wallet1,wallet2);cout<<wallet1<<" "<<wallet2<<endl; // 350 300swapp(&wallet1,&wallet2);cout<<wallet1<<" "<<wallet2<<endl; // 300 350swapv(wallet1,wallet2);cout<<wallet1<<" "<<wallet2<<endl;// 300 350return 0; } void swapr(int &a,int &b) {int temp;temp = a;a = b;b = temp; } void swapp(int *a,int *b) {int p;p = *a;*a = *b;*b = p;} void swapv(int a,int b) {int temp;temp = a;a = b;b = temp; }在swapr()中變量a,b是wallet1,wallet2的別名,所以兩者交換也將wallet1,2的值進(jìn)行了交換,但swapv()中的a和b是復(fù)制了wallet1,2的新變量,將它倆交換并不影響main()中的變量的值,因此需要利用指針指出wallet1,2內(nèi)存所在的地址方可進(jìn)行交換。
2.3 引用與結(jié)構(gòu)
引用非常適合用于結(jié)構(gòu)和類,假設(shè)有如下結(jié)構(gòu)定義:
struct free {string name;int made;int attempts;float percent; }則可以這樣編寫函數(shù)原型,在函數(shù)中將指向該結(jié)構(gòu)的引用作為參數(shù):
void set_pc(free& ft); void display(const free& ft);//倘若不想修改傳入的結(jié)構(gòu),關(guān)鍵詞const #include <iostream> #include <string> struct free_throws {std::string name;int made;int attempts;float percent; };void display(const free_throws & ft); void set_pc(free_throws & ft); free_throws & accumulate(free_throws &target, const free_throws &source);int main() {free_throws one = {"Ifelsa Branch", 13, 14};free_throws two = {"Andor Knott", 10, 16};free_throws three = {"Minnie Max", 7, 9};free_throws four = {"Whily Looper", 5, 9};free_throws five = {"Long Long", 6, 14};free_throws team = {"Throwgoods", 0, 0};free_throws dup;set_pc(one);display(one);accumulate(team, one);display(team); // use return value as argumentdisplay(accumulate(team, two));accumulate(accumulate(team, three), four);display(team); // use return value in assignmentdup = accumulate(team,five);std::cout << "Displaying team:\n";display(team);std::cout << "Displaying dup after assignment:\n";display(dup);set_pc(four); // ill-advised assignmentaccumulate(dup,five) = four;//five的數(shù)據(jù)給到dup中,再用four覆蓋dupstd::cout << "Displaying dup after ill-advised assignment:\n";display(dup);// std::cin.get();return 0; }void display(const free_throws & ft) {using std::cout;cout << "Name: " << ft.name << '\n';cout << " Made: " << ft.made << '\t';cout << "Attempts: " << ft.attempts << '\t';cout << "Percent: " << ft.percent << '\n'; } void set_pc(free_throws & ft) {if (ft.attempts != 0)ft.percent = 100.0f *float(ft.made)/float(ft.attempts);elseft.percent = 0; }free_throws & accumulate(free_throws & target, const free_throws & source) {target.attempts += source.attempts;target.made += source.made;set_pc(target);return target; }何時(shí)使用引用參數(shù)
對(duì)于使用傳遞的值不做修改的函數(shù):
①數(shù)據(jù)對(duì)象很小,如內(nèi)置數(shù)據(jù)類型或小型結(jié)構(gòu),則按值傳遞;
②數(shù)據(jù)對(duì)象是數(shù)組,則使用指針,并聲明為const
③數(shù)據(jù)對(duì)象是大型結(jié)構(gòu),則使用const指針或者const引用,節(jié)省復(fù)制結(jié)構(gòu)所需的時(shí)間和空間
④數(shù)據(jù)對(duì)象是類對(duì)象,使用const引用
對(duì)于修改調(diào)用函數(shù)中數(shù)據(jù)的函數(shù)
①數(shù)據(jù)對(duì)象是內(nèi)置數(shù)據(jù)類型,則使用指針
②數(shù)據(jù)對(duì)象是數(shù)組,則只能使用指針
③數(shù)據(jù)對(duì)象是結(jié)構(gòu),則使用引用或指針
④數(shù)據(jù)對(duì)象是類對(duì)象,使用引用
默認(rèn)參數(shù)
默認(rèn)參數(shù)指的是當(dāng)函數(shù)調(diào)用中省略了實(shí)參時(shí)自動(dòng)使用的一個(gè)值。
設(shè)置默認(rèn)值必須通過函數(shù)原型:
對(duì)于帶參數(shù)列表的函數(shù),必須從右向左添加默認(rèn)值
int harp(int n, int m=2, int j=3);//可用int hard(int n,int m =3, int j);//不可用int saiji(int n =5, int m =1, int j =9);//可用實(shí)參從左到右的順序依次賦給相應(yīng)的形參,而不能跳過任何參數(shù)。只有在函數(shù)原型中指明了默認(rèn)值,函數(shù)定義與沒有默認(rèn)參數(shù)時(shí)完全相同。
函數(shù)重載
默認(rèn)參數(shù)能夠使用不同數(shù)目的參數(shù)調(diào)用同一個(gè)函數(shù),而函數(shù)多態(tài)(函數(shù)重載)能夠使用多個(gè)同名的函數(shù),多態(tài)是指有多種形式,重載是指有多個(gè)重名的函數(shù),兩個(gè)術(shù)語是一回事,但通常使用函數(shù)重載。
函數(shù)重載的關(guān)鍵是函數(shù)的參數(shù)列表,也成為函數(shù)特征標(biāo),如果兩個(gè)函數(shù)的參數(shù)數(shù)目,排列順序都相同,則它們的特征標(biāo)相同,變量名無關(guān)緊要。函數(shù)重載的條件就是特征標(biāo)不同。
上述函數(shù)的特征標(biāo)均不相同,并且返回類型也可以不同,因此可認(rèn)為是函數(shù)重載。
double cube(double x); double cube(double &x);編譯器在檢查函數(shù)特征標(biāo)時(shí),把類型的引用與類型本身視為同一個(gè)特征標(biāo)。
函數(shù)模板
函數(shù)模板是通用的函數(shù)描述,使用泛型來定義函數(shù),其中的泛型可用具體的類型(int,double等)替換,函數(shù)模板允許以任意類型的方式定義函數(shù),如以下模板所示:
template<class T>//第一行template必需,class與typename可替換,必須使用尖括號(hào) void swap(T& a,T& b)//類型名可以任意選擇,但命名規(guī)則要遵守 {T temp;temp = a;a = b;b = temp; } // funtemp.cpp -- using a function template #include <iostream> // function template prototype template <typename T> // or class T void Swap(T &a, T &b);int main() {using namespace std;int i = 10;int j = 20;cout << "i, j = " << i << ", " << j << ".\n";cout << "Using compiler-generated int swapper:\n";Swap(i,j); // generates void Swap(int &, int &)cout << "Now i, j = " << i << ", " << j << ".\n";double x = 24.5;double y = 81.7;cout << "x, y = " << x << ", " << y << ".\n";cout << "Using compiler-generated double swapper:\n";Swap(x,y); // generates void Swap(double &, double &)cout << "Now x, y = " << x << ", " << y << ".\n";// cin.get();return 0; }// function template definition template <typename T> // or class T void Swap(T &a, T &b) {T temp; // temp a variable of type Ttemp = a;a = b;b = temp; }顯式具體化
C++98標(biāo)準(zhǔn):
①對(duì)于給定的函數(shù)名,可以有非模板函數(shù)、模板函數(shù)和顯式具體化函數(shù)及其重載版本
②顯示具體化的原型和定義應(yīng)以template<>打頭,并通過原型指出類型
③具體化優(yōu)先于常規(guī)模板,而非模板函數(shù)優(yōu)于具體化和常規(guī)模板
實(shí)例化與具體化
代碼中包含函數(shù)模板本身并不會(huì)生成函數(shù)定義, 只是一個(gè)用于生成函數(shù)定義的方案,當(dāng)編譯器使用模板為特定類型生成函數(shù)定義時(shí),得到的便是函數(shù)實(shí)例,例如上述swap(i,j)便是模板函數(shù)swap()的一個(gè)實(shí)例,這種實(shí)例化的方式成為隱式實(shí)例化。
顯式實(shí)例化的語法是聲明所需的種類,用<>表示類型,并在聲明前加上關(guān)鍵字template:
顯式具體化,顯式實(shí)例化,隱式實(shí)例化統(tǒng)稱為具體化,相同之處在于表示的都是使用具體類型的函數(shù)定義,而不是通用描述。前綴template與前綴template<>分別代表顯示實(shí)例化和顯式具體化
編譯器選擇哪個(gè)函數(shù)版本
完全匹配和最佳匹配
①指向非const數(shù)據(jù)的指針和引用優(yōu)先與非const指針和引用參數(shù)匹配
②const和非const之間的區(qū)別只適用于指針和引用指向的數(shù)據(jù)
③完全匹配優(yōu)于另一個(gè)的情況還有一個(gè)是非模板函數(shù),而另一個(gè)不是,此時(shí)非模板函數(shù)優(yōu)于模板函數(shù)(包括顯式具體化)
④如果兩者都是模板函數(shù),那么較具體的模板函數(shù)優(yōu)先。
部分排序規(guī)則
重載解析尋找最匹配的函數(shù):
如果只存在一個(gè)這樣的函數(shù),則選擇它;
如果存在多個(gè)這樣的函數(shù),但其中只有一個(gè)是非模板函數(shù),則選擇非模板函數(shù);
如果存在多個(gè)合適的函數(shù),并且都為模板函數(shù),但只有一個(gè)比其他更具體,則選擇該函數(shù);
如果有多個(gè)同樣合適的非模板或模板函數(shù),但沒有一個(gè)更具體的,則會(huì)報(bào)錯(cuò);
如果不存在匹配的,也會(huì)報(bào)錯(cuò)
關(guān)鍵詞decltype(C++11)
decltype (x+y)xpy;//xpy的類型為x+y的類型 xpy = x+y;//等價(jià)于decltype(x+y)xpy=(x+y)decltype (expression) var
decltype的確定類型:
①如果expression是一個(gè)沒有用括號(hào)括起的標(biāo)識(shí)符,則var與該標(biāo)識(shí)符的類型相同,包括const等限定符;
②如果expression是一個(gè)函數(shù)調(diào)用,則var與函數(shù)返回類型相同;
long indeed(int); decltype(indeed(3))m;//m是long類型,并且函數(shù)沒有實(shí)際調(diào)用③如果expression是一個(gè)左值,則var指向其類型的引用,一種顯而易見的情況就是expression是用括號(hào)括起的標(biāo)識(shí)符;
double xx = 4.4; decltype((xx))r2 = xx;//r2是一個(gè)double的引用 decltype(xx)W = xx;//w是一個(gè)double④如果前面條件都不滿足,那么var與expression類型相同
int j=3; int &k =j; int &n =j; decltype(j+6)x;//x為int decltype(100L)y;//y為long decltype(k+n)z;//z為int,k,n為引用,但兩者相加得到的是int后置返回類型(C++11)
對(duì)于下面的原型:
double h(int,float);使用新增的語法可編寫成:
auto h(int,float) -> double;//auto是一個(gè)占位符,表示后置返回類型提供的類型總結(jié)
以上是生活随笔為你收集整理的2020 我的C++的学习之路 第八章函数的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2020 我的C++学习之路 C++Pr
- 下一篇: 2020 我的C++学习之路 C++Pr