return
語句將終止當前正在執行的函數並將控制權返回到調用該函數的地方,兩種形式:
return;
return expression;
無返回值的函數
沒有返回值的函數只能用在返回類型是 void
的函數中,返回 void
的函數不要求非得有 return
語句,因為這類函數的最后一句后面會隱式的執行 return
。
有返回值的函數
只要函數的返回類型不是 void
,則該函數內的每條 return
語句必須返回一個值, return
語句返回值的類型必須與函數的返回類型一致,或者能夠隱式轉換成函數返回類型。
在含有 return
語句的循環后面應該也有一條 return
語句,如果沒有的話,程序就是錯誤的。
值是如何被返回的
返回一個值的方式和初始化一個變量或者形參的方式是完全一樣的:返回的值用於初始化調用點的一個臨時兩,該臨時兩就是函數調用的結果。
string make_plural(size_t ctr, const string &word, const string &ending)
{
return (ctr > 1) ? word + ending : word;
}
該函數的返回類型是 string
,意味着返回值將被拷貝到調用點,因此函數返回 word
的副本或者一個未命名的臨時 string
對象,該對象的內容是 word + ending
。
如果函數返回引用:
const string &shorterString(const string &str1, const string &str2)
{
return str1.size() <= str2.size() ? str1 : str2;
}
其中形參和返回類型都是 const string
的引用,無論是在函數調用還是返回結果都不會真正拷貝 string
對象。
不要返回局部對象的引用或指針
函數執行完成之后,它所占用的存儲空間會被釋放,因此函數終止意味着局部變量的引用指向的不再是有效的內存區域。
const string &manip()
{
string ret;
if (ret.empty())
return ret; //錯誤,返回的是局部對象的引用
else
return "empty"; //錯誤,"empty"是一個局部臨時變量
}
返回局部對象的引用是錯誤的,同樣返回局部對象的指針也是錯誤的。
引用返回左值
調用一個返回引用的函數得到左值,其它返回類型都是右值。
可以為返回類型是非常量引用的函數賦值,返回常量引用則不可以賦值。
char &get_val(string &str,string::size_type ix)
{
return str[ix];
}
int main()
{
string s("a value");
get_val(s,0) = 'A'; //返回非常量引用可以賦值
}
列表初始化返回值
C++ 11規定,函數可以返回花括號包圍起來的列表。
- 類似於其他類型的返回值,此處的列表也用來對表示函數返回的臨時量進行初始化。
- 如果列表為空,臨時量執行值初始化;否則,返回的值由函數的返回類型決定。
- 如果函數返回的是內置類型,則花括號包圍的列表最多包含一個值,並且該值所占用的空間不應該大於目標類型的空間;如果函數返回的是類類型,由類本身定義初始值如何使用。
vector<string> process(const string &expected)
{
if (expected.empty())
{
return{}; //返回空列表
}
else if (expected == "actual")
{
return{"functionX","okay"};
}
else
{
return{ "functionX","expected","actual"};
}
}
主函數main 的返回值
上面說到如果函數的返回值不是 void
,那么它必須返回一個值,但是這條規定有一個意外:允許 main
函數沒有 return
語句直接結束。
- 如果到達了
main
的末尾並且沒有遇到return
語句,編譯器會隱式地插入一條返回 0 的return
語句。 main
的返回值可以看作是狀態指示器,返回 0 表示執行成功,返回其他值表示執行失敗,其中非0返回值的具體定義由機器定義。- 為了使函數的返回值與機器無關,在
cstdlib
中 定義了兩個預處理變量:EXIT_SUCCESS
,EXIT_FAILURE
,使用這兩個變量分別表示成功與失敗。
返回數組的指針
因為數組不能拷貝,所以函數無法返回數組,但是,函數可以返回數組的指針或引用。
// 使用類型別名
typedef int arrT[10]; //arrT 是一個類型別名,它表示的類型是含有10個整型元素的數組
using arrT = int[10]; //與上面的聲明形式是等價的
arrT* func(int i); //定義一個返回指向10個整數數組的指針
注意:
int arr[10]; //arr是一個含有10個整數的數組
int *p1[10]; //p1是一個含有10個int* 的數組
int (*p2)[10] = &arr; //p2是一個指針,它指向的是包含10個int類型的數組
如果不使用類型別名,定義一個返回數組指針的函數,通用形式是:
Type (*function(parameter_list))[dimension]
Type
表示元素的類型;dimension
表示數組的大小;(*function(parameter_list))
兩端的括號必須存在,如果沒有括號,則函數返回的類型是指針的數組。
int (*func(int i))[10];
理解上面表達式的含義:
func(int i)
表示調用函數時需要一個int
類型的實參。(*func(int i))
意味着可以對函數調用的結果執行解引用操作。(*func(int i))[10]
意味着解引用函數調用的結果將是大小是10的數組。int (*func(int i))[10]
意味着數組中的元素都是int
類型。
使用尾置返回類型
C++ 11中規定了一種可以簡化上面 func
聲明的方法,就是使用 尾置返回類型。
任何函數的定義都可以使用尾置返回類型,但是這種形式對於返回類型比較復雜的函數最有效。
比如返回類型是數組的指針或者數組的引用,尾置返回類型會在函數的形參列表后面加一個->
符號開頭,為了表示函數真正的返回類型跟在形參列表之后,本應該放置返回類型的地方放一個 auto
:
auto func(int i)->int(*)[10];//func接受一個int類型的實參返回一個指針,該指針指向含有10個整數的數組
使用decltype
還有一種情況,如果我們知道函數返回的指針指向哪個數組,就可以使用 decltype
關鍵字聲明返回類型。
int odd[] = {1,3,5,7,9};
int ecen[] = {0,2,4,6,8};
// 返回一個指針,該指針指向含有5個整數的數組
decltype(odd) * arrPtr(int i)
{
return (i % 2) ? &odd : &even;
}
arrPtr
使用關鍵字 decltype
表示它返回的類型是指針,並且該指針所指向的對象與 odd
的類型一致。
需要注意的是 decltype
並不負責把數組類型轉換成對應的指針,所以 decltype
的結果是一個數組,要想表示 arrPtr
返回指針,還必須在函數聲明時加上*
。