函数的返回类型不能是数组类型或函数类型,但可以是指向数组或函数的指针
const形参和实参
允许定义若干有相同名字的函数,前提是不同函数的形参列表要有明显的区别
void fcn ( const int i) { }
void fcn ( int i) { }
指针或引用形参与const
int i = 42 ;
const int * cp = & i;
const int & r = i;
const int & r2 = 42 ;
int * p = cp;
int & r3 = r;
int & r4 = 42 ;
_______________________________________
void reset ( int * ip) { * ip = 0 ; }
void reset ( int & i) { i = 0 ; }
int i = 0 ;
const int ci = i;
string:: size_type ctr = 0 ;
reset ( & i) ;
reset ( & ci) ;
reset ( i) ;
reset ( ci) ;
reset ( 42 ) ;
不能把const对象、字面值或需要类型转换的对象传递给普通的引用形参
如果有函数
string:: size_type find_char ( string & s, char c, string:: size_type & occurs) ;
函数调用
find_char ( "HelloWorld" , 'o' , ctr) ;
将发生错误,相当于不能int & n = 42 ,string & s = "HelloWorld" 也是错的
但是改成
string:: size_type find_char ( const string & s, char c, string:: size_type & occurs) ;
就没问题
数组形参
因为1.不允许拷贝数组 2.使用数组时通常将其转换为指针。所以为函数传递数组时实际上是传递数组首元素的指针
void print ( const int * ) ;
void print ( const int [ ] ) ;
void print ( const int [ 10 ] ) ;
void print ( int ( & arr) [ 10 ] )
{
for ( auto elem : arr)
cout << elem << endl;
}
void print ( int ( * matrix) [ 10 ] , int row) ;
void print ( int matrix[ ] [ 10 ] , int row) ;
main
int main(int argc, char *argv[]),当实参传给main后,argv的第一个元素指向程序的名字或一个空字符串,接下来的元素依次传递命令行提供的实参。argc表示数组中的字符串数量
含有可变形参的函数
函数如果实参数量未知且实参类型全部相同,可以传递一个名为initializer_list的标准库类型 和vector一样initializer_lis也是模板类型。但是initializer_list对象中的元素永远是常量值,所以不能改变initializer_list对象中的元素值
void error_msg ( initializer_list< string> il)
{
for ( auto beg = il. begin ( ) ; beg != il. end ( ) ; ++ beg)
cout << * beg << " " ;
cout << endl;
}
if ( expected != actual)
error_msg ( { "functionX" , expected, actual} ) ;
else
error_msg ( { "functionX" , "okay" } ) ;
含有initializer_list形参的函数也可以同时拥有其他形参
void error_msg ( ErrCode e, initializer_list< string> il)
{
cout << e. msg ( ) << ": " ;
for ( const auto & elem : il)
cout << elem << " " ;
cout << endl;
}
if ( expected != actual)
error_msg ( ErrOcde ( 42 ) , { "functionX" , expected, actual} ) ;
else
error_msg ( ErrCode ( 0 ) , { "functionX" , "okay" } ) ;
返回语句
const string & manip ( )
{
string ret;
if ( ! ret. empty ( ) )
return ret;
else
return "Empty" ;
}
引用返回左值
调用一个返回引用的函数得到左值,其余返回类型得到右值
char & get_val ( string & str, string:: size_type ix) { return str[ ix] ; }
int main ( )
{
string s ( "a value" ) ;
cout << s << endl;
get_val ( s, 0 ) = 'A' ;
cout << s << endl;
return 0 ;
}
返回数组指针
typedef int arrT[ 10 ] ;
using arrT = int [ 10 ] ;
arrT* func ( int i) ;
不使用类型别名则返回数组指针的函数形式是类型 (*函数(参数列表))[维度]
int ( * func ( int i) ) [ 10 ] ;
int arr[ ] = { 1 , 2 , 3 } ;
decltype ( arr) * arrPtr ( int i)
{
. . .
return & arr;
}
函数重载
拥有顶层const的形参无法和一个没有const的形参区分开来(之前说过,顶层const会被忽略)
int fun ( int ) ;
int fun ( const int ) ;
int fun ( int * ) ;
int fun ( int * const ) ;
如果形参是某种类型的指针或引用,那就能通过指向的是常量还是非常量来实现重载(现在是底层const)
int fun ( int & ) ;
int fun ( const int & ) ;
int fun ( int * ) ;
int fun ( const int * ) ;
重载和作用域
在内层作用域中声明名字,将隐藏外层作用域中声明的同名实体
string read ( ) ;
void print ( const string & ) ;
void print ( double ) ;
void fooBar ( int ival)
{
bool read = false ;
string s = read ( ) ;
void print ( int ) ;
print ( "abc" ) ;
print ( ival) ;
}
默认实参
一旦某个形参被赋予了默认值,它后面所有形参都必须有默认值 局部变量不能作为默认实参
内联函数和constexpr函数
一般吧规模较小、流程直接、调用频繁的函数定义为内联函数。在函数名前加上inline表示为内联 因为内联函数的定义对编译器而言必须可见,所以要把内联函数的声明和定义都放在头文件中。 constexpr函数的返回类型及所有形参的类型都得是字面值类型,并且函数体中必须有且只有一个return constexpr函数不一定返回常量表达式
函数匹配
void f ( ) ;
void f ( int ) ;
void f ( int , int ) ;
void f ( double , double = 3.14 ) ;
f ( 5.6 ) ;
匹配第一步选定候选函数(与被调用函数同名且可见的函数)。4个f全部选上 第二步根据实参选出可行函数(形参数量与调用提供的实参数量相同,且对应的类型相同或能转换成形参类型的函数)。选出f(int)
和f(double, double = 3.14)
,这两个都能使用一个实参调用 第三步从可行函数中选择与本次调用最匹配的函数,即实参类型与形参类型越接近越好。这里选出f(double, double = 3.14)
如果调用f(42, 2.56)
,就第一个实参来看会发现void f(int, int)
更好,而第二个实参和void f(double, double = 3.14)
更匹配。这时会发生二义性。
函数指针
bool lengthCompare ( const string & , const string & ) ;
bool ( * pf) ( const string & , const string & ) ;
pf = lengthCompare;
pf = & lengthCompare;
bool b1 = pf ( "abc" , "def" ) ;
bool b2 = ( * pf) ( "abc" , "def" ) ;
bool b3 = lengthCompare ( "abc" , "def" ) ;
不能定义函数类型的形参,但是形参可以是指向函数的指针
void f ( const string & s1, const string & s2, bool pf ( const string & , const string & ) ) ;
void f ( const string & s1, const string & s2, bool ( * pf) ( const string & , const string & ) ) ;
f ( s1, s2, lengthComapre) ;
typedef bool func ( const string & , const string & ) ;
typedef decltype ( lengthCompare) func2;
typedef bool ( * funcp) ( const string & , const string & ) ;
typedef decltype ( lengthCompare) * funcp2;
void f ( const string & , const string & , func) ;
void f ( const string & , const string & , funcp2) ;
using F = int ( int * , int ) ;
using pf = int ( * ) ( int * , int ) ;
pf f1 ( int ) ;
f f1 ( int ) ;
f * f1 ( int ) ;
int ( * f1 ( int ) ) ( int * , int ) ;