天天看點

【高品質代碼】如何寫出更高品質的C/C++代碼(2):函數設計1、引言:2、聲明函數:3、函數的實作

函數是組成C/C++程式的基本元素,是将一段執行某項功能的代碼進行了封裝的代碼段。為了實作設計的功能,函數的功能正确性是首要的前提,但是僅僅是正确還不夠,其設計的科學性和合理性也是影響函數使用的重要因素。本文簡要讨論C/C++函數設計和實作的一些基本規則。

每一個完整的C/C++函數都至少包含三個部分:傳回值、函數名和參數。函數參數和傳回值承擔了調用者與被調用函數之間資料傳遞的功能,主要方式有三種:值傳遞、指針傳遞和引用傳遞,前兩者為C标準,引用傳遞為C++标準。其中引用傳遞的性質類似于指針傳遞,但是使用方式類似值傳遞。

聲明函數主要考慮函數的參數和傳回值的問題。當然,函數名也是重要的一部分,在設計函數名時,應當注意函數名展現函數的功能,且不産生歧義。通常使用一句英文表示的一個動作或特性來作為函數名,單詞之間通過大小寫轉換來區分。

函數的參數應當書寫完整,不應隻寫類型而省略參數名稱。當函數沒有參數時,使用void作為參數。

參數名稱要科學命名,應反映傳遞給該參數的實際意義,不要簡單使用a、b等簡單的命名。如一個計算矩形面積的函數,可以聲明成如下形式:

如果函數包括輸入參數和輸出參數,一般輸出參數(即目的參數)放在前面,輸入參數(即源參數)放在後面。如字元串拷貝函數:

有些僅僅作為輸入資料,在函數内部不能修改的參數指針,可以聲明為const類型進行保護,這樣一旦函數體内視圖修改該參數,則會産生錯誤。如果傳值參數僅作為輸入參數,則可聲明為const &類型,省去臨時對象的構造和析構過程,提高效率。如上面GetRectArea函數的參數都可以聲明為const &類型,StringCopy函數的strDst參數可以聲明為const類型:

一些簡單的函數,由于幾乎不可能出現錯誤,且一般隻有一個計算結果,那麼可以将計算結果通過傳回值傳遞給調用者。對于複雜函數,傳回值通常用于傳回錯誤辨別,而計算結果通過輸出參數獲得。如果需要傳回多個參數,除了定義多個輸出參數外,還可以定義一個輸出結構體,在輸出之前将輸出值封裝在一個結構體對象中整體傳回。

函數傳回值的類型有“傳回值”和“傳回引用”兩種設計。其差別是,“傳回值”會産生一個臨時變量作為函數傳回值的副本,而“傳回引用”時不會産生值的副本。有些時候選擇“傳回引用”可以提高效率,而有些時候必須“傳回值”否則可能出錯。

首先需要注意到一個問題就是,絕對不要傳回局部對象的引用,因為局部對象在函數調用結束之後就會被釋放,引用指向的對象會是一片未知區域。比如以下代碼是不允許出現的:

在類的實作函數中,如果該函數傳回的是該對象自身,那麼可以通過this指針傳回該對象的引用。典型的例子如string的指派函數:

在通過傳回this指針的對象到引用時,不會把本地對象拷貝到上層函數的對象記憶體,而是直接傳回目前對象本身,降低了不必要的開銷,提高了效率。

函數的實作方法千差萬别,然而在函數體的一開始以及傳回時可以對參數和傳回值進行檢查以防止不必要的錯誤發生。

可以使用assert防止非法參數,這樣可以預防許多程式的錯誤。assert是僅在debug模式下生效的宏定義,用于檢查不應該發生的情況。如以下函數中,采用assert防止輸入參數為空:

需要注意的事項有:

不可以傳回指向棧對象的指針或者引用,因為棧對象在傳回時将被銷毀;

傳回值的類型(值/指針/引用)應與函數聲明一緻;

考慮傳回對象的效率;

對于提高傳回對象的效率而言,臨時對象是否在棧中建立和銷毀是不同的。如以下代碼:

此時,程式的流程如下:

建立temp對象,調用拷貝構造函數初始化;

調用拷貝構造函數将temp複制到外部存儲單元;

函數結構,調用析構函數銷毀temp對象。

而使用以下方式:

此時,臨時對象将直接建立在外部存儲單元中,不再調用拷貝構造函數和析構函數,效率更高。

繼續閱讀