第6章 函数

6.1 函数基础

函数包括:返回类型、函数名称、形参列表、函数体

函数调用:①用实参初始化形参;②控制权交给被调函数。
return语句:①返回return语句的值;②控制权转移到主调函数。

warming

函数的返回类型不能是数组类型或者函数类型,但可以是指向数组和函数的指针。

函数体内定义的自动对象,在函数结束后被销毁。
函数体内定义的静态对象,在程序中只定义一次。

函数声明也叫函数原型,一般在头文件中,不含有函数体。

6.2 参数传递

函数调用时,都会重新创建形参,并使用实参初始化形参。

值传递和指针传递,都是将实参内存对应的数据,拷贝到形参对应的内存中。

使用引用传递,是将形参绑定到初始化它的对象。(个人认为是指针传递的一个便捷写法,是一个语法糖)

noting

尽量使用引用,从而避免拷贝。如果函数中不修改实参,应该使用const限定。

使用引用,还可以通过参数,返回函数中的内容。

数组形参

数组:①不允许拷贝;②使用数组名,通常会转换成指针。

//以下定义等价,编译器忽略数组长度
//定义成const,不能通过指针修改数组值,若需要修改,不适用const
void print(const int*);
void pirnt(const int[]);
void print(const int[10]);

//通常需要指明数组大小,或者结束标记
//如果是C字符串,可以通过最后位的'\0'判断结束
void print(const int *beg, const int *end);
void print const int ia[], const size_t size);

//数组引用形参,维度是类型的一部分
//这一做法可以使用sizeof判断数组占用的字节数
//这一做法也限定了,只能使用大小为10的数组
void print(int (&arr)[10]);

多维数组:

//matrix指向数组的首元素,此元素是10个整数的指针
void print(int (*matrix)[10], int rowSize);

//matrix实际上指向了含有一维整数的数组的开头
//10被编译器忽略
void print(int matrix[][10], int rowSize);

main函数

//二者等价
int main(int argc, char *argv[]);
int main(int argc, char **argv);

可变形参的函数

initializer_list形参:参数数量未知,类型相同。

//定义时
void error_msg(ErrCode e, initializer_list<string> msgs);
//调用时,可以看出,实际上还是两个参数,第二参数使用了列表
error_msg(ErrCode(0), {"function error", "Number error"});

省略符形参

仅仅为了访问特殊的C代码,这些代码使用了varargs的C标准库功能。大多说类型对象在传递给省略符形参时,无法正确拷贝,所以一般不用。

定义方式:void foo(param_list, ...);例如C中的printf函数。

6.3 函数的返回值

函数返回的是return之后的副本。

warming

由于在函数体内部定义的所有对象在函数结束后都会销毁,所以返回局部变量的指针或引用,将会出现未定义的情况。

函数返回左值

只有函数的返回值是引用的时候,返回的值才是左值,其他都是右值。

可以将返回类型为非常量左值的函数结果赋值。

//函数定义
char &get_val(string &str);
//函数使用
get_val(str) = 'A';

返回一个列表

vector<string> process()
{
    //...
    return {str1, str2, str3};
}

返回数组指针或引用

因为数组不能被拷贝,所以只能返回数组的指针或者引用。

//
using arrT = int[10];
arrT *func(int i);

//
int ( *func(int i) )[10];

//③尾置返回类型
auto func(int i) -> int(*)[10];

//
int odd[10]={};
decltype(odd) *func(int i);

6.4 函数重载

const形参

//顶层const无法区分
Record lookup(Phone);
Record lookup(const Phone);

//底层const可以区分
Record lookup(Phone*);
Record lookup(const Phone*);

重载中使用const_cast

//希望如果传递的参数是const的,返回也是const
//传递的参数不是const的,返回也不是const
const string &shorterString(const string &s1, const string &s2)
{
    return s1.size() <= s2.size() ? s1 : s2;
}
string &shorterString(string &s1, string &2)
{
    auto &r = shorterString(const_cast<const string&>(s1),
                                     const_cast<const string&>(s2));
    return const_cast<string &>(r);
}

6.5 特殊特性

默认实参

函数调用时,用默认实参初始换形参,因此,默认实参可以被一个明确的函数赋值。

内联函数

inline

constexpr函数

隐式内联的。

是可以用在常量表达式中的函数。

函数返回的不一定是常量,此时如用在常量表达式中,编译器会报错。

6.7 函数指针

bool lengthCompare(const string &, const strng&);

//声明指向该函数的指针,未初始化
bool (*pf)(const string &, const strng&);

//初始化该指针,&可选,二者等价
pf = lengthCompare;    //自动转换成指针
pf = &lengthCompare;

//使用指针调用,*可选
bool b1 = pf("hello", "world!");
bool b1 = (*pf)("hello", "world!");

//使用类型别名
    //函数类型,使用时自动转换为指针
typedef bool Func(const string &, const strng&);
typedef decltype(lengthCompare) Func;
    //指向函数的指针类型
typedef bool (*Func)(const string &, const strng&);
typedef decltype(lengthCompare) *Func;


//函数指针做形参,三者等价
void useBigger(const string &, const strng&,
                      bool (*pf)(const string &, const strng&));//显式声明了指针参数
void useBigger(const string &, const strng&,
                      bool pf(const string &, const strng&));
void useBigger(const string &, const strng&, Func);

//声明返回函数的指针的函数
bool (*function(...)) (const string &, const strng&);
Func function(...);    //使用类型别名
auto function(...) -> bool (*)(const string &, const strng&);    //尾置类型
decltype(lengthCompare) function(...);

 

posted on 2015-05-05 13:03  峰入云  阅读(274)  评论(0编辑  收藏  举报

导航