读书笔记||函数探幽
一、C++內(nèi)聯(lián)函數(shù)
內(nèi)聯(lián)函數(shù)是C++為提高程序運(yùn)行速度所做的改進(jìn)。常規(guī)函數(shù)和內(nèi)聯(lián)函數(shù)之間的主要區(qū)別不在于編寫方式,而在于C++編譯器如何將他們組合到程序中。
編譯過程的最終產(chǎn)品是可執(zhí)行程序。運(yùn)行程序時(shí),操作系統(tǒng)將這些指令載入到計(jì)算機(jī)內(nèi)存中,因此每條指令都有特定的內(nèi)存地址。計(jì)算機(jī)隨后將逐步執(zhí)行這些指令。有時(shí)候循環(huán)或者分支語句,將跳過一些指令,向前或向后跳到特定的地址。常規(guī)函數(shù)調(diào)用也使程序跳到另一個(gè)函數(shù)的地址,并在函數(shù)結(jié)束時(shí)返回。執(zhí)行函數(shù)調(diào)用指令時(shí),程序?qū)⒃诤瘮?shù)調(diào)用后立即存儲(chǔ)該指令的內(nèi)存地址,并將函數(shù)參數(shù)復(fù)制到堆棧,保留內(nèi)存塊,跳到標(biāo)記函數(shù)起點(diǎn)的內(nèi)存單元,執(zhí)行函數(shù)代碼(也許還需將返回值放入寄存器中),然后跳回到地址被保存的指令處。
C++內(nèi)聯(lián)函數(shù)提供了另一種選擇。內(nèi)聯(lián)函數(shù)的編譯代碼與其他程序代碼的“內(nèi)聯(lián)”起來,也就是說,編譯器將使用相應(yīng)的函數(shù)代碼替換函數(shù)調(diào)用。對(duì)于內(nèi)聯(lián)代碼,程序無需跳到另一個(gè)位置處執(zhí)行代碼,再跳回來。因此,內(nèi)聯(lián)函數(shù)的運(yùn)行速度比常規(guī)函數(shù)稍快,但代價(jià)是需要占用更多的內(nèi)存。
應(yīng)該有選擇地使用內(nèi)聯(lián)函數(shù)。如果執(zhí)行函數(shù)代碼地時(shí)間比處理函數(shù)調(diào)用機(jī)制地時(shí)間長,則節(jié)省的時(shí)間將只占用整個(gè)過程的很小一部分。如果代碼執(zhí)行時(shí)間很短,則內(nèi)聯(lián)調(diào)用使用大部分時(shí)間。另一方面,由于這個(gè)過程相當(dāng)快,因此節(jié)省了該過程的大部分時(shí)間,但節(jié)省的時(shí)間絕對(duì)值并不大,除非函數(shù)值經(jīng)常被調(diào)用。
要使用這項(xiàng)特性,必須采取下述措施之一:
1.在函數(shù)聲明前加上關(guān)鍵字inline;
2.在函數(shù)定義前加上關(guān)鍵字inline。
通常的做法是省略原型,將整個(gè)定義(即函數(shù)頭和所有函數(shù)代碼)放在本應(yīng)提供原型的地方。
內(nèi)聯(lián)函數(shù)和常規(guī)函數(shù)一樣,也是按值來傳遞的,如果參數(shù)為表達(dá)式即4.5+7.5,則函數(shù)將傳遞表達(dá)式的值12。這使得C++內(nèi)聯(lián)功能遠(yuǎn)遠(yuǎn)勝過C語言的宏定義。
盡管程序沒有提供獨(dú)立的原型,但C++原型特性仍在起作用。這是因?yàn)樵诤瘮?shù)首次使用前出現(xiàn)整個(gè)函數(shù)定義充當(dāng)了原型,這意味著可以給square()傳遞int和long值,將值傳遞給函數(shù)前,程序自動(dòng)將這個(gè)值強(qiáng)制轉(zhuǎn)換為double類型。
二、引用變量
C++新增了一種復(fù)合類型——引用變量。引用是已定義的變量的別名,如果將twain作為clement變量的引用,則可以交替使用twain和clement來表示該變量。引用變量的主要用途是用作函數(shù)的形參。通過將引用變量用作參數(shù),函數(shù)將使用原始數(shù)據(jù),而不是其副本,這樣除指針之外,引用也為函數(shù)處理大型結(jié)構(gòu)提供了一種非常方便的途徑,同時(shí)對(duì)于設(shè)計(jì)類來說,引用是必不可少的。
1.創(chuàng)建引用變量
C和C++使用&符號(hào)來指示變量的地址。C++給&符號(hào)賦予了另一個(gè)含義,將其用來聲明引用。
其中,&不是地址運(yùn)算符,而是類型標(biāo)識(shí)符的一部分。就像聲明中的char*指的是指向char的指針一樣,int&指的是指向int的引用。
#include <iostream> int main() {using namespace std;int rats = 101;int & rodents = rats; // rodents is a referencecout << "rats = " << rats;cout << ", rodents = " << rodents << endl;rodents++;cout << "rats = " << rats;cout << ", rodents = " << rodents << endl; // some implementations require type casting the following // addresses to type unsignedcout << "rats address = " << &rats;cout << ", rodents address = " << &rodents << endl;// cin.get();return 0; }
int & rodents = rats;中的&運(yùn)算符不是地址運(yùn)算符,而是將rodents的類型聲明為int&,即指向int變量的引用,
但是, cout << ", rodents address = " << &rodents << endl;中的&的運(yùn)算符是地址運(yùn)算符,其中&rodents表示rodents引用的變量的地址。
在上述的例子中,rats和rodents的值和地址都相同,將rodents加1將影響這兩個(gè)變量的值,更準(zhǔn)確的講rodents++操作講一個(gè)有兩個(gè)名稱的變量加1。
表達(dá)式rodents和*prats都可以同rats互換,而表達(dá)式&rodents和prats都可以同&rats互換。從這一點(diǎn)來講,引用看上去很像偽裝表達(dá)式的指針,但是引用又不同于指針,除了表示法不同以外,差別之一就是必須在聲明引用時(shí)將其初始化,而不能像指針那樣,先聲明,再賦值。
int rat; int & rodent; rodent = rat; //No,you can't do this. //必須在聲明引用變量時(shí)進(jìn)行初始化。引用更接近c(diǎn)onst指針,必須在創(chuàng)建時(shí)進(jìn)行初始化,一旦與某個(gè)變量關(guān)聯(lián)起來,就將一直效忠于它,也就是說:
int & rodents = rats ;
實(shí)際上是下述代碼的偽裝表示:
int * const pr =&rats;
最初,rodents引用的是rats,隨后程序試圖將rodents作為bunnies的引用:rodents=bunnies;
這種意圖是成功的,因?yàn)閞odents的值從101變?yōu)榱?0。但是同時(shí)rats也變成了50,同時(shí)rats和rodents的地址也相同,而該地址與bunnies的地址不同。由于rodents是rats的別名,因此上述賦值語句與下面的語句等效:rats = bunnies;
也就是說,這意味著將bunnies變量的值賦給rat變量,簡而言之,可以通過初始化聲明來設(shè)置引用,但是不能通過賦值來設(shè)置。
2.將引用用作函數(shù)參數(shù)
引用經(jīng)常被用作函數(shù)參數(shù),使得函數(shù)中的變量名成為調(diào)用程序中的變量的別名。這種傳遞參數(shù)的方法稱為按引用傳遞。按引用傳遞允許被調(diào)用的函數(shù)能夠訪問調(diào)用函數(shù)中的變量。
交換兩個(gè)變量的值:交換函數(shù)必須能夠修改調(diào)用程序中變量的值。這意味著按值傳遞變量將不管用,因?yàn)楹瘮?shù)將交換原始變量副本的內(nèi)容,而不是變量本身的內(nèi)容。但是傳遞引用時(shí),函數(shù)可以使用原始數(shù)據(jù),另一種方法是,傳遞指針來訪問原始數(shù)據(jù)。
void swapr(int & a, int & b); //pass variables
void swapp(int * p, int * q); //pass addresses of variables
void swapv(int a, int b); //pass values of variables
按引用傳遞swapr和按值傳遞swapv看起來相同。只能通過原型或函數(shù)定義才能知道swapr是按引用傳遞。然而地址運(yùn)算符&使得按地址傳遞swapp。
3.引用的屬性個(gè)特別之處
refcube()函數(shù)修改了main()中x的值,而cube()沒有,這提醒我們?yōu)楹瓮ǔ0粗祩鬟f,變量a位于cube()中,它被初始化x的值,但修改a并不會(huì)影響x。但由于refcube()使用了引用參數(shù),因此修改ra實(shí)際上就是修改x。
創(chuàng)建臨時(shí)變量:1.實(shí)參的類型是正確,但不是左值;2.實(shí)參的類型不正確,但可以轉(zhuǎn)換為正確的類型。
4.將引用用于結(jié)構(gòu)
引用引入主要是為了用于結(jié)構(gòu)和類,而不是基本的內(nèi)置類型。
使用結(jié)構(gòu)引用參數(shù)的方式與使用基本變量引用相同,只需在聲明結(jié)構(gòu)參數(shù)時(shí)使用引用運(yùn)算符&即可。
5.將引用用于類對(duì)象
將類對(duì)象傳遞給函數(shù)時(shí),C++通常的做法是使用引用。可以通過使用引用,讓函數(shù)將類string、ostream、istream、ofstream和i發(fā)stream等類的對(duì)象作為參數(shù)。
6.何時(shí)使用引用參數(shù)
主要原因:1.能夠修改調(diào)用函數(shù)中的數(shù)據(jù)類型;2.通過傳遞引用而不是整個(gè)數(shù)據(jù)對(duì)象,可以提高程序的運(yùn)行速度。
三、默認(rèn)參數(shù)
默認(rèn)參數(shù)指的是當(dāng)函數(shù)調(diào)用中省略了實(shí)參時(shí)自動(dòng)使用的一個(gè)值。如果將void wow(int n)設(shè)置成n個(gè)有默認(rèn)值為1,則函數(shù)調(diào)用wow()相當(dāng)于wow(1)。這極大地提高了使用函數(shù)的靈活性。
#include <iostream> const int ArSize = 80; char * left(const char * str, int n = 1); int main() {using namespace std;char sample[ArSize];cout << "Enter a string:\n";cin.get(sample,ArSize);char *ps = left(sample, 4);cout << ps << endl;delete [] ps; // free old stringps = left(sample);cout << ps << endl;delete [] ps; // free new string// cin.get();// cin.get();return 0; } // This function returns a pointer to a new string // consisting of the first n characters in the str string. char * left(const char * str, int n) {if(n < 0)n = 0;char * p = new char[n+1];int i;for (i = 0; i < n && str[i]; i++)p[i] = str[i]; // copy characterswhile (i <= n)p[i++] = '\0'; // set rest of string to '\0'return p; }
該程序使用new創(chuàng)建一個(gè)新的字符串,以存儲(chǔ)被選擇的字符。
四、函數(shù)重載
默認(rèn)參數(shù)是能夠讓使用不同數(shù)目的參數(shù)調(diào)用一個(gè)函數(shù),而函數(shù)重載能夠使用多個(gè)同名的函數(shù)。“函數(shù)重載”指的是可以有多個(gè)同名的函數(shù),因此對(duì)名稱進(jìn)行重載。
函數(shù)重載的關(guān)鍵是函數(shù)的參數(shù)列表——也稱為函數(shù)特征標(biāo)。如果兩個(gè)函數(shù)的參數(shù)數(shù)目和類型相同,同時(shí)參數(shù)的排列順序也相同,則它們的特征標(biāo)相同,而變量名是無關(guān)緊要的。
只有當(dāng)函數(shù)基本上執(zhí)行相同的任務(wù),但使用不同形式的數(shù)據(jù)時(shí),才采用函數(shù)重載。
五、函數(shù)模塊
函數(shù)模塊是通用的函數(shù)描述,也就是使用泛型來定義函數(shù),其中泛型可用具體的類型(int或者double)替換。通過將類型作為參數(shù)傳遞給模板,也可以使用編譯器生成該類型的函數(shù)。
由于模板允許以泛型(而不是具體類型)的方式來編寫程序,因此有時(shí)候也被稱為通用編程,由于類型是用參數(shù)表示的,因此模板特性有時(shí)也被稱為參數(shù)化類型。
建立一個(gè)交換模板:
第一行指出,要建立一個(gè)模板,并將類型命名為AnyType,關(guān)鍵字template和typename是必需,除非可以使用關(guān)鍵字class和typename。另外,必須使用尖括號(hào)。類型名可以任意選擇,只要遵循C++的命名規(guī)則即可。模板不創(chuàng)建任何函數(shù),而只是告訴編譯器如何定義函數(shù)。
將模板放在頭文件中,并在需要使用模板的文件中包含頭文件。
函數(shù)模板自動(dòng)完成重載函數(shù)的過程。只需使用泛型和具體算法來定義函數(shù),編譯器將為程序中使用的特定參數(shù)類型生成正確的函數(shù)定義。
總結(jié)
以上是生活随笔為你收集整理的读书笔记||函数探幽的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 简单明了的网站结构设计呦!
- 下一篇: MacBook Pro 方向左键不能用