第六章 函数
函数基础
局部对象
名字有作用域,对象有生命周期(lifetime)
自动对象(automatic object):当函数的控制路径经过变量定义语句时创建该对象,当达到定义所在的块末尾时销毁它。
局部静态对象:程序执行路径第一次经过对象定义语句时初始化,知道程序终止才被销毁。
函数声明
参数传递
如果形参是引用类型,它将绑定到对应的实参上;否则,将实参的值拷贝后赋给形参。
- 如果无需修改引用形参的值,最好将其声明为常量引用。
main:处理命令行选项
假设main函数位于可执行文件prog内,我们可以向程序传递下面的选项:
prog -d -o ofile data0
这些命令通过两个可选的形参传递给main函数:
int main(int argc, char *argv[]) {...} //或: int main(int argc, char **argv) {...}
当实参传给main函数之后,argv的第一个元素指向程序的名字或者一个空字符串,接下来的元素一次传递命令行提供的实参。最后一个指针只会掉元素值保证为0。
- 以上面的命令行为例:
argc = 5;argv[0] = prog;argv[1] = -d;argv[2] = -o;argv[3] = ofile;argv[4] = data0;argv[5] = 0;
含有可变形参的函数
initializer_list形参
其类型定义在同名的头文件中
提供如下操作:
initializer_list<T> lst; //默认初始化,T类型元素的空列表
initializer_list<T> lst{a,b,c...};
//lst的元素数量和初始值一样多;lst的元素是对应初始值的副本;列表中的元素是const
lst2(lst)
lst2 = lst //拷贝或复制一个initializer_list对象不会拷贝列表中的元素;拷贝后,原始列表和副本元素共享
lst.size() //列表中元素的数量
lst.begin() //返回指向lst中首元素的指针
lst.end() //返回指向lst中尾元素下一位置的指针
返回类型和return语句
引用返回左值,其他返回类型得到右值。
列表初始化返回值:C++11新标准规定,函数可以返回花括号包围的值的列表。
主函数main的返回值
允许main函数没有返回值(若没有,编译器隐式地插入return 0)
返回0表示执行成功,其他值依机器而定。
为了使返回值与机器无关,cstdlib头文件定义了两个预处理变量,分别表示成功和失败:
return EXIT_FAILURE;
return EXIT_SUCCESS;
//因为它们是预处理变量,所以既不能在前面加上std::,也不能在using声明里出现。
返回数组指针
使用类型别名
typedef int arrT[10]; //arrT是一个类型别名,它表示的类型是含有10个整数的数组
using arrT = int[10]; //与上一句等价
arrT* func(int i); //func返回一个指向含有10个整数的数组的指针声明一个返回数组指针的函数,形式如下
Type (*function(parameter_list)) [dimension]
//Type表示返回的数组指针指向的数组元素类型
//dimension表示数组的大小
//例如:
int (*func(int i)) [10];使用尾置返回类型(C++11)
auto func(int i) -> int(*)[10];使用decltype
int odd[] = {1,3,5,7,9};
int even[] = {0,2,4,6,8};
decltype(odd) *arrPtr(int i)
{
return (i % 2) ? &odd : &even; //返回一个指向数组的指针
}
函数重载
如果同一作用域内的几个函数名字相同但形参列表不同,我们称之为重载(overloaded)函数。
不允许两个函数除了返回类型外其他所有要素都相同。
重载与作用域:一旦在当前作用域中找到了所需的名字,编译器就会忽略掉外层作用域中的同名实体。
特殊用途语言特性
介绍三种函数相关的语言特性:默认实参、内联函数、constexpr函数。
默认实参
内联函数(inline)
调用函数一般比求等价表达式的值要慢,内联函数可避免函数调用的开销。
- 将函数指定为内联函数,通常就是将它在每个调用点上“内联地”展开。
constexpr函数
内联函数和constexpr函数通常定义在头文件中
调试帮助
程序可以包含一些用于调试的代码,但这些代码只在开发程序时使用。当应用程序编写完成准备发布时,要先屏蔽掉调试代码。这种方法用到两项预处理功能:assert和NDEBUG。
assert预处理宏
#include <cassert>assert(expr);//首先对expr求值,//如果表达式为假(即0),assert输出信息并终止程序的执行。//如果表达式为真(即非0),assert什么也不做。//例如:对一个文本进行操作的程序可能要求所给定单词的长度都大于某个阈值。assert(word.size() > threshold;
NDEBUG预处理变量
assert的行为依赖于一个名为NDEBUG的预处理变量的状态。如果定义了NDEBUG,则assert什么也不做。默认状态下没有定义NDEBUG,此时assert将运行执行时检查。
使用#define语句定义NDEBUG,从而关闭调试状态。
很多编译器都提供了命令行选项使我们可以定义预处理变量。
$ CC -D NDEBUG main.C #微软编译器中用 /D这只是调试程序的辅助手段,不能代替真正的逻辑检查,也不能代替程序本应该包含的错误检查。
除了assert以外,也能使用NDEBUG编写自己的条件调试代码:
//如果定义了NDEBUG,#ifndef和#endif之间的代码将被忽略void print(const int ia[], aize_t size) { #ifndef NDEBUG //_ _func_ _是编译器定义的一个局部静态变量,用于存放函数的名字,它是const char的一个静态数组。 cerr << _ _func_ _ << array size is << size << endl; #endif}
除了_ _ func _ _之外,还有其它四个名字:
_ _FILE_ _ 存放文件名的字符串字面值 _ _LINE_ _ 存放当前行号的整型字面值 _ _TIME_ _ 存放文件编译时间的字符串字面值 _ _DATA_ _ 存放文件编译日期的字符串字面值
函数指针
bool lengthCompare(const string &, const string &);//pf指向一个函数,该函数的参数是两个const string的引用,返回值是bool类型。注意圆括号必不可少bool (*pf) (const string &, const string &); //未初始化
pf = lengthCompare; //pf指向名为lengthCompare的函数pf = &lengthCompare; //等价赋值语句,&是可选的
//此三个调用等价bool b1 = pf(hello, goodbye);bool b2 = (*pf)(hello, goodbye);bool b3 = lengthCompare(hello, goodbye);
参考:C++Primer第五版
相关文章:
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。