第六章:函数

一、参数传递

1、形参为引用类型时,将绑定到相应的实参上,否则为实参的拷贝;在C++中建议用引用类型代替指针

2、const 形参:

  • 对于顶层的const,在函数形参中无效,也不能构成重载函数
  • 形参中尽量使用常量引用,对于普通引用会有误导,主要是非常量引用会导致函数不能接受常量的类型

3、数组形参:传递给函数的值为数组的首元素指针,所以一开始不知道数组的大小,有三种解决方法

  • 如果是C风格的字符串,则要保证字符串中最后一个字符为空字符
  • 传递数组的首元素好尾后元素的指针,使用begin和end函数
  • 传入数组指针和数组的大小

4、数组引用形参:如果形参是数组的引用,则维度是类型的一部分,不可少

void print(int (&arr)[10])    //(&arr)[10]:括号不可少
{    
    ...
}

5、传递多维数组:数组的第二维及后面的维度为数组类型的一部分,不能省略

void print(int (*matrix)[10], int rowSize);    rowSize为数组第一维的长度

6、main函数的输入

  • argv用户输入的实参从argv[1]开始,argv[0]为保存程序的名字
  • argc为字符串的数量

二、返回类型和return语句

1、注意不要返回局部对象的引用或指针,局部变量会在函数返回后清空数据

2、如果函数返回的类型是可修改的左值,那么也可以直接作为左值来呗赋值

3、C++11可以返回{}内的列表:如vector,类等,如果只是sting,int这种{}内只能有一个值

4、返回数组指针:可以有很多的方式,但是最简单的是使用类型别名

    • C++11提供了尾置返回类型来代表函数的返回类型
auto func(int i) -> int(*)[10]
int (*func(int i))[10]

三、函数重载形参数量或形参类型上有所不同,不允许两个函数除了返回类型外其他所有要素都相同

1、const形参和重载

Record lookup(Phone);
Record lookup(const Phone);        //重复定义Record lookup(Phone);

Record lookup(Phone *);
Record lookup(Phone * const);    //重复定义Record lookup(Phone *);

Record lookup(Account &);
Record lookup(const Account &);    //底层const引用可以

Record lookup(Account *);
Record lookup(const Account *);    //底层const指针可以
  • 顶层const的形参和另一个没有顶层const的形参无法区分
  • 底层的const可以区分;如果传递了一个非const的对象时,编译器会优先选择非常量版本:编译器会选择与实参最佳匹配的函数

2、const_cast和重载:存在常量的版本,通过const_cast设计非常量的版本

3、重载与作用域:不同的作用域中无法重载函数名

4、调用重载函数时应尽量强制类型转换

四、特殊用途语言特性

1、默认实参:一旦某个形参被赋予了默认值,则它后面的所有形参都要有默认值(C中没有这个属性)

2、内联函数和constexpr函数:通常都定义在头文件中

    • 在函数返回类型前加上关键字inline可以被声明为内联函数
    • 内联函数可以避免函数调用的开销(C99后C支持,GUN C支持)
    • 内联机制用于优化规模小、流程直接、频繁使用的函数
    • constexpr函数:返回类型和形参的类型都是子明类型,而且函数体中必须有且只有一条return语句
    • constexpr函数被隐式地指定为内联函数
constexpr int new_sz(int i) {return i*3;}

3、调试帮助:

    • assert预处理宏:包含在cassert头文件中
assert(expr);    //对expr求值,为假则终止程序运行;为真assert什么都不做
检查”不能发生的事“
    • NDEBUG预处理:#define NDEBUG : assert会无效
    • 特殊代码
__func__        :输出当前调试的函数名字:GCC两个都支持
__FUNCTION__    :输出当前调试的函数名字(VC,VS中用这个)
__FILE__        :存放文件名的字符串字面值
__LINE__    :存放当前行号的整形字面值
__TIME__    :存放文件编译时间的字符串字面值
__DATE__    :存放文件编译日期的字符串字面值

五、函数指针:函数的类型由它的返回类型和形参类型共同决定,与函数名无关

1、使用函数指针:把函数名作为一个值使用时,该函数会自动转换成指针

bool lengthCompare(const string &, const string &);
函数类型:bool(const string &, const string &)
pf = lengthCompare;
pf = &lengthCompare;    //取地址符可选
  • 编译器通过指针类型决定选用哪个函数,指针类型必须与重载函数中的某一个精确匹配,包括返回类型和参数类型

2、函数指针形参:编译器自动把函数类型转换为指针

void useBigger(const string &s1, const string &s2, bool pf(const string &, const string &));
void useBigger(cosnt string &s1, const string &s2, bool(*pf)(const string &, const string &));    //两个等价

3、返回指向函数的指针:这里编译器不会自动将函数返回类型当成对应的指针类型,所以必须自己处理好

    • 还是使用类型别名比较方便
using F = int(int *, int);
using PF = int (*)(int *, int);
PF f1(int);
F *f1(int);       //F为函数类型,需要自己加*来变为指针
  • decltype适用于某个函数时,返回的是函数类型而非指针类型
posted @ 2015-09-23 14:59  dylqt  阅读(138)  评论(0编辑  收藏  举报