亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

高質量C++/C編程指南 -- 第6章 函數設計

2019-11-17 05:18:20
字體:
來源:轉載
供稿:網友

  第6章 函數設計
函數是C++/C程序的基本功能單元,其重要性不言而喻。函數設計的細微缺點很輕易導致該函數被錯用,所以光使函數的功能正確是不夠的。本章重點論述函數的接口設計和內部實現的一些規則。 函數接口的兩個要素是參數和返回值。C語言中,函數的參數和返回值的傳遞方式有兩種:值傳遞(pass by value)和指針傳遞(pass by pointer)。C++ 語言中多了引用傳遞(pass by reference)。由于引用傳遞的性質象指針傳遞,而使用方式卻象值傳遞,初學者經常迷惑不解,輕易引起混亂,請先閱讀6.6節“引用與指針的比較”。6.1 參數的規則
l 【規則6-1-1】參數的書寫要完整,不要貪圖省事只寫參數的類型而省略參數名字。假如函數沒有參數,則用void填充。例如:void SetValue(int width, int height); // 良好的風格void SetValue(int, int); // 不良的風格float GetValue(void); // 良好的風格float GetValue(); // 不良的風格l 【規則6-1-2】參數命名要恰當,順序要合理。例如編寫字符串拷貝函數StringCopy,它有兩個參數。假如把參數名字起為str1和str2,例如void StringCopy(char *str1, char *str2);那么我們很難搞清楚究竟是把str1拷貝到str2中,還是剛好倒過來??梢园褏得制鸬酶幸饬x,如叫strSource和strDestination。這樣從名字上就可以看出應該把strSource拷貝到strDestination。還有一個問題,這兩個參數那一個該在前那一個該在后?參數的順序要遵循程序員的習慣。一般地,應將目的參數放在前面,源參數放在后面。假如將函數聲明為:void StringCopy(char *strSource, char *strDestination);別人在使用時可能會不假思考地寫成如下形式:char str[20];StringCopy(str, “Hello World”); // 參數順序顛倒l 【規則6-1-3】假如參數是指針,且僅作輸入用,則應在類型前加const,以防止該指針在函數體內被意外修改。例如:void StringCopy(char *strDestination,const char *strSource);l 【規則6-1-4】假如輸入參數以值傳遞的方式傳遞對象,則宜改用“const &”方式來傳遞,這樣可以省去臨時對象的構造和析構過程,從而提高效率。2 【建議6-1-1】避免函數有太多的參數,參數個數盡量控制在5個以內。假如參數太多,在使用時輕易將參數類型或順序搞錯。2 【建議6-1-2】盡量不要使用類型和數目不確定的參數。C標準庫函數PRintf是采用不確定參數的典型代表,其原型為:int printf(const chat *format[, argument]…);這種風格的函數在編譯時喪失了嚴格的類型安全檢查。6.2 返回值的規則
l 【規則6-2-1】不要省略返回值的類型。C語言中,凡不加類型說明的函數,一律自動按整型處理。這樣做不會有什么好處,卻輕易被誤解為void類型。C++語言有很嚴格的類型安全檢查,不答應上述情況發生。由于C++程序可以調用C函數,為了避免混亂,規定任何C++/ C函數都必須有類型。假如函數沒有返回值,那么應聲明為void類型。l 【規則6-2-2】函數名字與返回值類型在語義上不可沖突。違反這條規則的典型代表是C標準庫函數getchar。例如:char c;c = getchar();if (c == EOF)…按照getchar名字的意思,將變量c聲明為char類型是很自然的事情。但不幸的是getchar的確不是char類型,而是int類型,其原型如下:int getchar(void); 由于c是char類型,取值范圍是[-128,127],假如宏EOF的值在char的取值范圍之外,那么if語句將總是失敗,這種“危險”人們一般哪里料得到!導致本例錯誤的責任并不在用戶,是函數getchar誤導了使用者。l 【規則6-2-3】不要將正常值和錯誤標志混在一起返回。正常值用輸出參數獲得,而錯誤標志用return語句返回。回顧上例,C標準庫函數的設計者為什么要將getchar聲明為令人迷糊的int類型呢?他會那么傻嗎?在正常情況下,getchar的確返回單個字符。但假如getchar碰到文件結束標志或發生讀錯誤,它必須返回一個標志EOF。為了區別于正常的字符,只好將EOF定義為負數(通常為負1)。因此函數getchar就成了int類型。我們在實際工作中,經常會碰到上述令人為難的問題。為了避免出現誤解,我們應該將正常值和錯誤標志分開。即:正常值用輸出參數獲得,而錯誤標志用return語句返回。函數getchar可以改寫成 BOOL GetChar(char *c);雖然gechar比GetChar靈活,例如 putchar(getchar()); 但是假如getchar用錯了,它的靈活性又有什么用呢?2 【建議6-2-1】有時候函數原本不需要返回值,但為了增加靈活性如支持鏈式表達,可以附加返回值。例如字符串拷貝函數strcpy的原型:char *strcpy(char *strDest,const char *strSrc);strcpy函數將strSrc拷貝至輸出參數strDest中,同時函數的返回值又是strDest。這樣做并非多此一舉,可以獲得如下靈活性:
char str[20];int length = strlen( strcpy(str, “Hello World”) ); 2 【建議6-2-2】假如函數的返回值是一個對象,有些場合用“引用傳遞”替換“值傳遞”可以提高效率。而有些場合只能用“值傳遞”而不能用“引用傳遞”,否則會出錯。例如:class String{…// 賦值函數String & Operate=(const String &other); // 相加函數,假如沒有friend修飾則只許有一個右側參數friend String operate+( const String &s1, const String &s2); private:char *m_data; }String的賦值函數operate = 的實現如下:String & String::operate=(const String &other){if (this == &other)return *this;delete m_data;m_data = new char[strlen(other.data)+1];strcpy(m_data, other.data);return *this; // 返回的是 *this的引用,無需拷貝過程}對于賦值函數,應當用“引用傳遞”的方式返回String對象。假如用“值傳遞”的方式,雖然功能仍然正確,但由于return語句要把 *this拷貝到保存返回值的外部存儲單元之中,增加了不必要的開銷,降低了賦值函數的效率。例如:String a,b,c;…a = b; // 假如用“值傳遞”,將產生一次 *this 拷貝a = b = c; // 假如用“值傳遞”,將產生兩次 *this 拷貝String的相加函數operate + 的實現如下:String operate+(const String &s1, const String &s2) {String temp;delete temp.data; // temp.data是僅含‘/0’的字符串temp.data = new char[strlen(s1.data) + strlen(s2.data) +1];strcpy(temp.data, s1.data);strcat(temp.data, s2.data);return temp;} 對于相加函數,應當用“值傳遞”的方式返回String對象。假如改用“引用傳遞”,那么函數返回值是一個指向局部對象temp的“引用”。由于temp在函數結束時被自動銷毀,將導致返回的“引用”無效。例如:c = a + b; 此時 a + b 并不返回期望值,c什么也得不到,流下了隱患。6.3 函數內部實現的規則
不同功能的函數其內部實現各不相同,看起來似乎無法就“內部實現”達成一致的觀點。但根據經驗,我們可以在函數體的“入口處”和“出口處”從嚴把關,從而提高函數的質量。l 【規則6-3-1】在函數體的“入口處”,對參數的有效性進行檢查。很多程序錯誤是由非法參數引起的,我們應該充分理解并正確使用“斷言”(assert)來防止此類錯誤。詳見6.5節“使用斷言”。l 【規則6-3-2】在函數體的“出口處”,對return語句的正確性和效率進行檢查。假如函數有返回值,那么函數的“出口處”是return語句。我們不要輕視return語句。假如return語句寫得不好,函數要么出錯,要么效率低下。注重事項如下:(1)return語句不可返回指向“棧內存”的“指針”或者“引用”,因為該內存在函數體結束時被自動銷毀。例如char * Func(void){char str[] = “hello world”; // str的內存位于棧上…return str; // 將導致錯誤}(2)要搞清楚返回的究竟是“值”、“指針”還是“引用”。(3)假如函數返回值是一個對象,要考慮return語句的效率。例如 return String(s1 + s2);這是臨時對象的語法,表示“創建一個臨時對象并返回它”。不要以為它與“先創建一個局部對象temp并返回它的結果”是等價的,如String temp(s1 + s2);return temp;實質不然,上述代碼將發生三件事。首先,temp對象被創建,同時完成初始化;然后拷貝構造函數把temp拷貝到保存返回值的外部存儲單元中;最后,temp在函數結束時被銷毀(調用析構函數)。然而“創建一個臨時對象并返回它”的過程是不同的,編譯器直接把臨時對象創建并初始化在外部存儲單元中,省去了拷貝和析構的化費,提高了效率。類似地,我們不要將 return int(x + y); // 創建一個臨時變量并返回它寫成int temp = x + y;return temp;由于內部數據類型如int,float,double的變量不存在構造函數與析構函數,雖然該“臨時變量的語法”不會提高多少效率,但是程序更加簡潔易讀。6.4 其它建議
2 【建議6-4-1】函數的功能要單一,不要設計多用途的函數。2 【建議6-4-2】函數體的規模要小,盡量控制在50行代碼之內。2 【建議6-4-3】盡量避免函數帶有“記憶”功能。相同的輸入應當產生相同的輸出。帶有“記憶”功能的函數,其行為可能是不可猜測的,因為它的行為可能取決于某種“記憶狀態”。這樣的函數既不易理解又不利于測試和維護。在C/C++語言中,函數的static局部變量是函數的“記憶”存儲器。建議盡量少用static局部變量,除非必需。
2 【建議6-4-4】不僅要檢查輸入參數的有效性,還要檢查通過其它途徑進入函數體內的變量的有效性,例如全局變量、文件句柄等。2 【建議6-4-5】用于出錯處理的返回值一定要清楚,讓使用者不輕易忽視或誤解錯誤情況。6.5 使用斷言
程序一般分為Debug版本和Release版本,Debug版本用于內部調試,Release版本發行給用戶使用。斷言assert是僅在Debug版本起作用的宏,它用于檢查“不應該”發生的情況。示例6-5是一個內存復制函數。在運行過程中,假如assert的參數為假,那么程序就會中止(一般地還會出現提示對話,說明在什么地方引發了assert)。void *memcpy(void *pvTo, const void *pvFrom, size_t size){assert((pvTo != NULL) && (pvFrom != NULL)); // 使用斷言byte *pBTo = (byte *) pvTo; // 防止改變pvTo的地址byte *pbFrom = (byte *) pvFrom; // 防止改變pvFrom的地址while(size -- > 0 )*pbTo ++ = *pbFrom ++ ;return pvTo;}
示例6-5 復制不重疊的內存塊assert不是一個倉促拼湊起來的宏。為了不在程序的Debug版本和Release版本引起差別,assert不應該產生任何副作用。所以assert不是函數,而是宏。程序員可以把assert看成一個在任何系統狀態下都可以安全使用的無害測試手段。假如程序在assert處終止了,并不是說含有該assert的函數有錯誤,而是調用者出了差錯,assert可以幫助我們找到發生錯誤的原因。很少有比跟蹤到程序的斷言,卻不知道該斷言的作用更讓人沮喪的事了。你化了很多時間,不是為了排除錯誤,而只是為了弄清楚這個錯誤到底是什么。有的時候,程序員偶然還會設計出有錯誤的斷言。所以假如搞不清楚斷言檢查的是什么,就很難判定錯誤是出現在程序中,還是出現在斷言中。幸運的是這個問題很好解決,只要加上清楚的注釋即可。這本是顯而易


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
一本大道久久加勒比香蕉| 91久久久久久久久久久| 日韩在线观看免费网站| 国产精品视频一区二区三区四| 亚洲性av在线| 国产精品久久久久一区二区| 亚洲午夜精品视频| 富二代精品短视频| 国产成人综合精品在线| 在线日韩中文字幕| 欧美性受xxxx白人性爽| 超在线视频97| 中文字幕综合一区| 91免费欧美精品| xxxxx91麻豆| 7777免费精品视频| 精品美女国产在线| 亚洲国产一区二区三区在线观看| 3344国产精品免费看| 国产成人激情小视频| 亚洲嫩模很污视频| 国产网站欧美日韩免费精品在线观看| 国产高清视频一区三区| 亚洲精品美女久久| 亚洲精品黄网在线观看| 国外成人免费在线播放| 欧美高清视频在线| 91精品在线国产| 欧美激情精品久久久久久免费印度| 亚洲综合小说区| 欧洲亚洲免费视频| 国外成人在线播放| 中文字幕一区二区三区电影| 国产精品国产三级国产aⅴ浪潮| 久久久人成影片一区二区三区| 97成人精品视频在线观看| 欧美激情欧美激情在线五月| 亚洲精品日韩激情在线电影| 成人性生交xxxxx网站| www.日韩.com| 91国内精品久久| 欧美性猛交xxxx乱大交极品| 亚洲欧美色图片| 国产婷婷成人久久av免费高清| 中日韩美女免费视频网站在线观看| 久久亚洲综合国产精品99麻豆精品福利| 日韩欧美亚洲综合| 91av网站在线播放| 精品亚洲一区二区| 狠狠躁天天躁日日躁欧美| 久久久影视精品| 久久综合免费视频| 97色伦亚洲国产| 日韩美女写真福利在线观看| 黑人巨大精品欧美一区免费视频| 欧美日韩一二三四五区| 久久91精品国产91久久跳| 成人黄色在线免费| 精品亚洲夜色av98在线观看| 国产亚洲精品一区二555| 欧美激情喷水视频| 97国产精品视频| 久久久久久噜噜噜久久久精品| 91超碰caoporn97人人| 国产精品久久久久久久久久久久久| 日韩欧美精品中文字幕| 久久久国产一区二区三区| 中文字幕久热精品视频在线| 亚洲美女免费精品视频在线观看| 国产成+人+综合+亚洲欧美丁香花| 日本高清视频精品| 亚洲国产精品va在看黑人| 国产综合香蕉五月婷在线| www.亚洲成人| 亚洲福利在线视频| 亚洲国产精品系列| 国产美女高潮久久白浆| 欧美激情久久久久久| 91精品国产高清自在线看超| 国产一区二区在线免费视频| 亚洲一级一级97网| 免费不卡在线观看av| 日本aⅴ大伊香蕉精品视频| 日本久久久久久久久| 欧美一级淫片aaaaaaa视频| 亚洲人成在线观| 亚洲欧美综合另类中字| 亚洲成人精品视频在线观看| 国产精品视频免费在线观看| 欧美视频在线观看 亚洲欧| 最新69国产成人精品视频免费| 91情侣偷在线精品国产| 欧美激情在线视频二区| 国产精品久久久久久久av大片| 日本中文字幕不卡免费| 国产不卡av在线| 成人欧美在线观看| 丝袜情趣国产精品| 3344国产精品免费看| 亚洲国产精品久久久| 国产网站欧美日韩免费精品在线观看| 成人黄色免费在线观看| 亚洲精品国产品国语在线| 亚洲国产欧美日韩精品| 91丝袜美腿美女视频网站| 91免费国产视频| 国产亚洲成精品久久| 91亚洲午夜在线| 夜夜嗨av一区二区三区免费区| 久久艳片www.17c.com| 亚洲国产日韩欧美在线图片| 国产精品天天狠天天看| 全球成人中文在线| 日韩免费av一区二区| 97国产精品视频| 神马国产精品影院av| 欧美成人免费网| 色老头一区二区三区在线观看| 亚洲成人精品久久| 国产欧美日韩精品丝袜高跟鞋| 亚洲天堂男人天堂女人天堂| 中文字幕亚洲综合久久| 欧美日韩亚洲视频一区| 在线中文字幕日韩| 91国产美女在线观看| 亚洲一区二区三区成人在线视频精品| 中文字幕免费精品一区| 亚洲视频axxx| 成人福利在线视频| www高清在线视频日韩欧美| 啊v视频在线一区二区三区| 亚洲丝袜在线视频| 日本一区二三区好的精华液| 九九热99久久久国产盗摄| 奇米四色中文综合久久| 欧美激情一级精品国产| 国产精品pans私拍| 色播久久人人爽人人爽人人片视av| 91精品国产成人| 中文字幕日韩有码| 亚洲欧美国产日韩天堂区| 欧美性极品少妇精品网站| 亚洲天堂男人的天堂| 高清一区二区三区日本久| 日韩欧美高清视频| 欧美体内谢she精2性欧美| 日韩av网址在线| 日韩三级影视基地| 国产三级精品网站| 国产美女被下药99| 国产精品久久久久久久久久新婚| 欧美性理论片在线观看片免费| 成人性生交大片免费看视频直播| www.久久撸.com| 日韩精品在线观看网站| 韩国v欧美v日本v亚洲| 国内精品国产三级国产在线专| 日韩中文在线中文网在线观看| 日韩精品高清视频| 亚洲第一页中文字幕| 亚洲天堂免费观看| 欧美又大又硬又粗bbbbb| 日韩性生活视频| 日韩av色在线|