c++函数
本文为阅读《c++ primer plus》函数的相关章节后做的小笔记,仅记录本人不熟悉或者容易犯错的地方
杂记
- c++中,函数的返回值不可以是数组,但是可以为其它的任何类型,例如整数、浮点数、指针、甚至可以是结构和对象
- 通常,函数通过将返回值复制到指定的CPU寄存器或者内存单元中将其返回,随后调用程序查看该内存单元,返回函数和调用函数必须就该内存单元中存储的数据的类型达成一致
- 函数原型不要求提供变量名,有类型列表就足够了
- c++中可以将const变量的地址赋给const指针,但是不可以将const变量的地址赋给常规指针
注意区分
int sloth = 3; const int * ps = &sloth; // a pointer to const int int * const finger = &sloth; // a const pointer to int
函数和二维数组
考虑如下场景
int data[3][4] = {{1,2,3,4}, {9,8,7,6}, {2,4,6,8}}; int total = sum(data, 3);
那么它们的函数原型是怎么样的呢?
- sum(int (*ar2)[4], int size),表面这是由一个指向4个int组成的数组的指针
- sum(int ar2[][4], int size),这种可读性比较强
函数和结构
- 可以按值传递结构,函数将会使用原始结构的副本;函数也可以返回结构,需要使用&地址运算符;但是如果结构非常大,复制结构就会增加内存要求。此时可以选择按引用传递
函数指针
- 和数据项相似,函数也有地址,函数的地址是储存其机器语言代码的内存的开始地址
获得函数的地址
- 只要使用函数名(不加参数)即可,即例如think()是一个函数,那么think就是该函数的地址
声明函数指针
一个估计时间的函数原型为:
double pam(int)
,那么正确的指针类型声明如下:double (*pf)(int)
- 因为pam是函数,那么
(*pf)
也是函数,那么pf就是指向函数指针
- 因为pam是函数,那么
那么就可以将函数作为参数传递了,例如estimate的函数原型:
estimate(int lines, double (*pf)(int))
,要让estimate函数使用pam函数,那么需要将pam的地址传递给它
使用指针调用函数
pf = pam;
double x = pam(3);
double y = (*pf)(5);
深入讨论函数指针
待
c++内联函数
常规的函数调用
- 执行到函数调用指令时,程序将在函数调用后立即存储该指令的内存地址,并将函数参数赋值到堆栈,跳到标记函数起点的内存单元,执行函数代码(也许还要将返回值放入寄存器中),最后再跳回地址被保存的指令处。这样子的来回跳转位置意味着以前使用函数时,需要一定的开销
c++提供另一种选择:内联函数
- 内联函数的编译代码与其它程序代码“内联”起来了,编译器将使用相应的函数代码替换函数调用,对于内联代码,程序无需跳到另一个位置处执行代码再跳回来,这样子运行速度会比常规的函数快,但是代价是需要占用更多的内存
使用内联函数
- 在函数声明前加入关键字inline
- 在函数定义前加上关键字inline
内联函数不可以递归
引用变量
- c++新增了一种复合类型:引用变量;引用是已经定义的变量的别名
- 引用变量主要用途是用作函数的形参,这样子函数就可以使用原始数据,而不是其副本,最经典的运用就是我们手写交换两个数的值的函数了;另外,当参数的结构比较大的时候,引用参数就会很有用
创建引用变量
int rats; int & rodents = rats;
&
不是地址运算符,而是类型标识符的一部分,上述声明允许将rats和rodents互换,它们指向相同的内存单元,有着一样的值引用和指针的差别
int rats = 100; int & rodents = rats; int * prats = &rats;
- rodents和
*prats
都可以和rats互换,都是表示100这个值 &rodents
和prats都可以和&rats
互换,都是得到rats的地址
- rodents和
通俗来讲:rodents是rats的别名而已,都是同一样东东,内存地址一样,值一样;而指针prats的值才是rats的内存地址,prats指针本身需要内存存储的
考虑调用函数时,参数不是一个变量的情况(例如函数原型为:
double refcube(const double &ra)
)double z = refcube(x + 3.0)
现代的c++认为是错误的,较老的编译器会发出警告。因为(x+3)不是double类型的变量,程序会创建一个临时无名变量,初始化值为(x+3.0),然后ra将会成为该临时变量的引用。实际上,当实参和引用参数不匹配时,c++将会产生临时变量,仅当参数为const引用时,c++才允许这样做 。编译器会在以下两种情况下生成临时变量- 实参类型正确,但不是佐左值
- 实参类型不正确,但可以转换为正确的类型
但是如果实参不匹配,那么函数的行为相当于按值传递,那么即使用了引用定义也没有什么用
6. 书本推荐尽可能使用const修饰
- 避免无意中修改数据
- const函数可以处理const和非const的实参,否则只可以接收const数据
使用const引用使函数能够正确生成并且使用临时变量
- 返回引用时需要注意
返回一个指向临时变量的引用是错误的做法,因为函数运行后就不再存在。同理,也应该避免返回指向临时变量的指针。解决方法:返回一个作为参数传递给函数的引用;另一种方法是使用new分配新的内存空间,但是记得最后释放内存
默认参数
- 设置函数的默认参数如:
char * left(const char * str, int n = 1)
,参数n的默认值为1,如果函数有默认值那么必须从右向左添加默认值
java不支持函数参数的默认值,但是这种功能可以通过函数重载实现
函数重载
属于函数重载
- 多个同名函数
- 使用不同的参数列表