C++函數傳回值的規則
- 【規則6-2-1】不要省略傳回值的類型。
C語言中,凡不加類型說明的函數,一律自動按整型處理。這樣做不會有什麼好處,卻容易被誤解為void類型。
C++語言有很嚴格的類型安全檢查,不允許上述情況發生。由于C++程式可以調用C函數,為了避免混亂,規定任何C++/ C函數都必須有類型。如果函數沒有傳回值,那麼應聲明為void類型。
- 【規則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誤導了使用者。
- 【規則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用錯了,它的靈活性又有什麼用呢?
- 【建議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”) );
- 【建議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什麼也得不到,流下了隐患。