日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++ primer第六章6.5函数的学习 之特殊用途的语言特性

發(fā)布時(shí)間:2023/12/13 c/c++ 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++ primer第六章6.5函数的学习 之特殊用途的语言特性 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

6.5.1 默認(rèn)實(shí)參

  • 將反復(fù)出現(xiàn)的數(shù)值稱為函數(shù)的默認(rèn)實(shí)參,調(diào)用含有默認(rèn)實(shí)參的時(shí)候可以包含該實(shí)參也可以不包含
  • 比如程序打開頁面會(huì)有一個(gè)默認(rèn)的寬高,如果用戶不喜歡也允許用戶自由指定與默認(rèn)數(shù)值不同的數(shù)值,具體例子如下圖所示
typedef string::size_type sz; string screen(sz ht = 24,sz wid = 80,char backgrnd = ' ');
  • 默認(rèn)實(shí)參作為形參的初始化數(shù)值出現(xiàn)在形參列表中,可以為一個(gè)或者多個(gè)形參定義成默認(rèn)數(shù)值,但是,一旦某個(gè)形參被賦予了默認(rèn)數(shù)值,這個(gè)形參之后的數(shù)值也必須有默認(rèn)數(shù)值。

使用默認(rèn)實(shí)參調(diào)用函數(shù)

  • 如果使用默認(rèn)的實(shí)參,調(diào)用函數(shù)的時(shí)候省略掉該實(shí)參就可以了。
  • 如上面提出的screen函數(shù),有三個(gè)變量,因此可以使用0、1、2、3個(gè)實(shí)參調(diào)用該函數(shù)
typedef string::size_type sz; string screen(sz ht = 24,sz wid = 80,char backgrnd = ' '); int main(){string window;window = screen();window = screen(1);window = screen(1,2);window = screen(1,2,'&'); }
  • window = screen(,,'&');//錯(cuò)誤,只可以忽略掉尾部的實(shí)參,即左邊的必須補(bǔ)齊定義,只有右邊的才可以缺省
  • 因此,在實(shí)際使用的場景中,需要設(shè)計(jì)形參的順序,將不怎么使用默認(rèn)形參的變量放在前面

默認(rèn)實(shí)參聲明

  • 對于函數(shù)的聲明來講,通常是將其放在頭文件中,并且每個(gè)函數(shù)聲明一次,但是多次聲明也是合法的。
  • 但是,在給定的作用域中,一個(gè)形參只可以賦予一次默認(rèn)實(shí)參。即,函數(shù)的后續(xù)聲明只能為之前那些沒有默認(rèn)值的形參添加默認(rèn)的實(shí)參,而且這個(gè)形參的左側(cè)的所有的形參都有默認(rèn)值。

默認(rèn)實(shí)參初始值

  • 局部變量不可以作為默認(rèn)的實(shí)參,只要表達(dá)式的類型可以轉(zhuǎn)化為形參所需要的類型,該表達(dá)式就可以作為默認(rèn)的實(shí)參。
typedef string::size_type sz; sz wd = 80; char def = ' '; sz ht(); string screen(sz = ht(),sz = wd,char = def); string window = screen();//調(diào)用screen(ht(),80,' ')
  • 用作默認(rèn)實(shí)參的名字,在函數(shù)聲明所在的作用域中解析,而這些名字的求值的過程發(fā)生在函數(shù)調(diào)用的時(shí)候
void f2(){def = '*';//改變默認(rèn)的實(shí)參的數(shù)值sz wd = 100;//隱藏了外層定義的wd,但是沒有改變默認(rèn)的數(shù)值window = screen();//調(diào)用了screen(ht(),80,'*') }
  • 在函數(shù)f2的內(nèi)部改變了def的值,所以對于screen的調(diào)用將會(huì)傳遞這個(gè)更新過的數(shù)值。
  • 對于wd,內(nèi)部聲明的局部變量會(huì)隱藏外部的wd,但是該局部變量并不會(huì)傳遞給screen的默認(rèn)的參數(shù)

6.5.2 內(nèi)聯(lián)函數(shù)和constexpr函數(shù)

定義函數(shù)的好處

  • 使用函數(shù)可以確保行為的統(tǒng)一,每次相關(guān)的操作都按照同樣的方式進(jìn)行
  • 如果需要修改計(jì)算的過程,顯然修改函數(shù)比先找到等價(jià)的表達(dá)式所有出現(xiàn)地方再逐一修改更加方便
  • 函數(shù)可以被其他應(yīng)用重復(fù)調(diào)用,省去了重新編寫開發(fā)的代價(jià)

壞處

  • 調(diào)用函數(shù)會(huì)比使用表達(dá)式慢,因?yàn)槭褂煤瘮?shù)要涉及到一系列的工作:調(diào)用前保存寄存器、并且在返回的是會(huì)恢復(fù);需要拷貝實(shí)參,程序需要在不同的新的位置上繼續(xù)執(zhí)行。

內(nèi)聯(lián)函數(shù)可以避免函數(shù)的調(diào)用所帶來的開銷

  • 將函數(shù)指定為內(nèi)聯(lián)函數(shù),通常是將它在每一個(gè)調(diào)用點(diǎn)上“內(nèi)聯(lián)地”展開,將會(huì)減少函數(shù)運(yùn)行使得開銷。
  • 在函數(shù)的前面加上關(guān)鍵字inline就可以將其聲明稱為內(nèi)聯(lián)函數(shù)
inline const string &shorterString(const string &s1,const string &s2){return s1.size() < s2.size() ? s1 : s2; }
  • 內(nèi)聯(lián)說明只是向編譯器發(fā)出一個(gè)請求,編譯器可以選擇忽略這個(gè)請求
  • 內(nèi)聯(lián)機(jī)制一般用于優(yōu)化規(guī)模較小,流程直接、頻繁調(diào)用的函數(shù),很多編譯器都不支持內(nèi)聯(lián)遞歸函數(shù),如果程序很大的話,也不大可能在調(diào)用點(diǎn)內(nèi)聯(lián)的展開

constexpr函數(shù)

  • constexpr是指可以用于常量表達(dá)式的函數(shù)。
  • 其函數(shù)的返回類型以及所有的形參的類型都得是字面值類型,而且函數(shù)體中必須有且只有一個(gè)return語句。
constexpr int new_sz() {return 42;} constexpr int foo = new_sz(); //正確,foo是一個(gè)常量的表達(dá)式
  • 把new_sz定義成無參數(shù)的constexpr函數(shù),因?yàn)榫幾g器能在程序編譯的時(shí)候驗(yàn)證new_sz函數(shù)返回的是常量的表達(dá)式,所以可以使用new_sz來初始化foo函數(shù)。
  • 執(zhí)行該初始化任務(wù)的時(shí)候,編譯器把constexpr函數(shù)的調(diào)用替換成其結(jié)果數(shù)值。為了能在編譯的過程中隨時(shí)展開,constexpr會(huì)被隱式轉(zhuǎn)變?yōu)閮?nèi)聯(lián)函數(shù)。
  • constexpr函數(shù)體內(nèi)也可以包含其他語句,只要這些語句在運(yùn)行的時(shí)候不執(zhí)行任何操作就可以。例如,constexpr函數(shù)內(nèi)可以有空的語句、類型別名以及using聲明。
  • 允許constexpr函數(shù)的返回值并非一個(gè)常量。
//如果arg是常量的表達(dá)式,則scale(arg)也是常量的表達(dá)式 constexpr size_t scale(size_t cnt){return new_sz() * cnt;//當(dāng)scale的實(shí)參是常量表達(dá)式的時(shí)候,返回的數(shù)值也是常量的表達(dá)式;反之不然; } int main(){int arr[scale(2)];//正確,scale(2)是常量的表達(dá)式int i = 2;int a2[scale(i)];//錯(cuò)誤,scale(i)不是常量的表達(dá)式 }

把內(nèi)聯(lián)函數(shù)和constexpr函數(shù)放在頭文件中

  • 和其他函數(shù)不一樣,內(nèi)聯(lián)函數(shù)和constexpr函數(shù)可以在程序中多次定義。畢竟,編譯器要想展開函數(shù)僅僅有函數(shù)的聲明是不夠的,還需要函數(shù)的定義。但是對于某個(gè)給定的內(nèi)聯(lián)函數(shù)或者constexpr函數(shù)來說,他的多個(gè)定義必須完全一致,因此通常將他們定義在頭文件中。

6.5.3 調(diào)試幫助

  • C++有些時(shí)候會(huì)用到一些類似于頭文件保護(hù)的技術(shù),從而可以有選擇的執(zhí)行代碼。
  • 基本思想是,程序包含一些用于調(diào)試的代碼,但是這些代碼只會(huì)在開發(fā)程序的時(shí)候使用,當(dāng)程序完準(zhǔn)備上線的時(shí)候,需要先屏蔽代碼,這就用到了兩項(xiàng)預(yù)先處理的功能:assert和NDEBUG

assert預(yù)處理宏

  • 預(yù)處理宏就是一個(gè)預(yù)處理變量,其行為類似于內(nèi)聯(lián)函數(shù)
  • assert使用一個(gè)表達(dá)式作為它的條件 assert(expr);? 首先對于expr進(jìn)行求值,如果表達(dá)式為假,assert會(huì)輸出信息并且終止程序的執(zhí)行。如果表達(dá)式為真,assert什么也不做
  • assert的頭文件會(huì)定義在cassert文件中,因?yàn)轭A(yù)處理名字是由預(yù)處理器而不是編譯管理,因此可以直接使用預(yù)處理名字而不需要提供using聲明。即直接使用assert,而不是std::assert,也不需要為assert提供using的聲明。
  • 和預(yù)處理的變量一樣,宏名字在程序內(nèi)部必須唯一。但是在實(shí)際編程的時(shí)候,即使沒有包含這個(gè)頭文件,也不要使用assert這個(gè)名字進(jìn)行任何相關(guān)的變量、函數(shù)、其他實(shí)體等的命名,因?yàn)?#xff0c;很多頭文件都會(huì)包含這個(gè)cassert,有可能通過其他途徑包含在程序中。
  • assert宏常常用于檢查“不能發(fā)生的條件”。例如,一個(gè)對于輸入文本進(jìn)行操作的語句對于輸入的長度有很大的要求,必須大于某一個(gè)指定的閾值。這個(gè)使用,程序可能會(huì)包含一個(gè)如下所示的語句? assert(word.size() > threshold );
  • assert都是一種調(diào)試程序的輔助手段,但是他不可以替代運(yùn)行時(shí)候的邏輯檢查,也不可以替代程序本身應(yīng)該包含的錯(cuò)誤檢查

NDEBUG預(yù)處理變量

  • assert的行為依賴于一個(gè)名為NDEBUG的預(yù)處理變量的狀態(tài)。如果定義了NDEBUG,那么assert就什么都不做。默認(rèn)情況下是沒有定義這個(gè)NDEBUG的,因此assert會(huì)執(zhí)行運(yùn)行檢查。
  • 使用#define NDEBUG 或者使用命令行進(jìn)行程序編譯的時(shí)候,使用 CC -D NDEBUG main.c 這兩者之間是等效的
  • 同理,也可以使用NDEBUG來編寫自己的條件調(diào)試的代碼,如果NDEBUG沒有定義,那么將會(huì)執(zhí)行#ifdef和#endif之間的代碼;如果定義了NDEBUG,那么這些代碼將會(huì)被忽略掉
  • #define NDEBUG
#ifdef NDEBUG// __func__是編譯器定義的一個(gè)局部靜態(tài)變量,用于存放函數(shù)的名字cerr << __func__ << ": array size is " << size << endl; #endif
  • __func__是一個(gè)const char的一個(gè)靜態(tài)數(shù)組,用于存放函數(shù)的名字

總結(jié)

以上是生活随笔為你收集整理的C++ primer第六章6.5函数的学习 之特殊用途的语言特性的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。