C++ Primer(第五版) 第六章 函数

目录

函数基础

1.局部对象

2.声明

参数传递

1.传值参数

2.传引用参数

3.const形参或实参

4.数组形参

 5.可变形参

返回类型与return语句

1.无返回值函数

2.有返回值函数

 3.返回数组指针

函数重载

特殊用途语言特性

1.默认实参

2.内联函数和constexpr函数

函数匹配

1.实参类型转换

函数指针


函数基础

 函数一般由返回值、函数名、参数列表和函数体组成。

string printTest(string name)
{
    return "Hello " + name;
}

调用函数

 调用函数形式为:函数名(参数列表)

printTest("yao");

 函数调用起到两个作用:一是中断当前主调函数,而是转到被调函数执行。

 形参与实参

 实参是用于函数调用时,初始化对应的形参。尽管实参与形参有着对应关系,但是却没有求值顺序。

函数返回类型

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

返回类型可以是void,但是不可以不写。

1.局部对象

 变量(对象)都有各自的生命周期和作用域,对于函数的形参及函数内变量,其生命周期及作用域仅存在于函数体内,这样的变量统称为局部变量。

局部变量会隐藏外部作用域声明的所有同名变量。

自动对象

我们把只存在执行期间的对象成为自动对象。即在进入块时创建,当块语句运行结束后,创建的自动变量销毁,其值变为未定义。

局部静态变量

 在局部变量声明前加上 static 限定词,则该自动变量变为一个局部静态变量。

局部静态变量仅在第一次经过对象定义语句时初始化,后续则不会销毁也不会再重新初始化,所以每次在函数体内变化后,下次调用还会是上次函数结束时的值。

2.声明

 函数声明可以多次,与定义的区别为没有函数体,用一个分号代替。

函数声明也叫函数原型。

参数传递

 参数传递分为值传递和引用传递。

值传递是指实参和形参是两个独立的对象,实参将值拷贝给形参。

引用传递是指形参为引用类型,传参时,形参绑定到实参上。

1.传值参数

 将普通类型(非指针)实参传递给形参时,形参的操作不会影响到实参的值。

指针形参

 当形参类型为指针时,实参也需要传递一个同类型指针,由于指针存在间址访问功能,所以此时形参也可以影响到实参。

2.传引用参数

 传引用参数有两个优点:

  • 当参数为容器类或者结构体等较大类型时,使用传值拷贝操作效率很低,而传引用则仅是名字的绑定
  • 当需要返回多个参数时,可以使用引用参数,在函数体内修改的形参会反应到实参

3.const形参或实参

 对于顶层const,在函数调用时是可以忽略的(即形参为顶层const,实参可以是无const类型)。

但是对于底层const,则传实参时必须与形参类型保持一致(包含const)。

注意:在我们对于函数的形参不需要进行修改时,尽量使用常量引用。

4.数组形参

void print(int *);
void print(int[]);
void print(int[10]);

 以上三种形式都为数组参数,其中第三个的10并不代表真实的数组维度。

对于数组参数的长度一般有三种表示方式

  • 特殊的结束标记。在数组内以特定的结束符标记(如'\0','\n'等)
  • 标准库规范。相仿于标准库,传递数组的首元素和尾后元素
  • 传入长度参数。

复杂数组形式

void print(int (&arr)[]);//数组引用形参
void print(int (*p)[]);//多维数组

 5.可变形参

 initializer_list

返回类型与return语句

 同函数调用一样,return语句也有两个类似的作用:一是结束当前的被调函数,二是将控制权交给主调函数。

return语句返回的类型必须与函数返回类型保持一致,或者能隐式转换,否则会报错。

1.无返回值函数

没有返回值的return只能用于返回类型为void的函数中。但是返回类型为void的函数不一定非要return,因为再其函数最后会隐式执行return语句。

2.有返回值函数

 return语句返回的类型必须与函数返回类型保持一致,或者能隐式转换,否则会报错。

值是如何被返回的

 如同初始化类似,函数返回后,会在函数调用点初始化一个临时量,这个临时量就是函数返回的结果。

对于普通类型局部变量,返回的是其副本。

对于复杂类型(引用、指针),则需要注意不能返回局部量。对于两者来说一方面返回的是一个局部量的绑定,另一方面返回的是一个指向局部作用域的指针,在函数返回后,函数内作用域被销毁,而此时两者指向的内容均在无效的函数作用域内。

 引用返回左值

 一个返回值为引用的函数,返回值可以作为一个左值,其他类型返回值为右值。

 递归

 一个函数如果调用了他自身,则称该函数为递归函数。递归函数一般需要有一个限制条件(即递归的次数),否则该函数将一直递归下去。

int factorial (int val)
{
    if(val>1)
        return factorial(val-1)*val;
    return 1;
}

 3.返回数组指针

函数重载

 几个函数名字相同但是形参列表不同,则称这几个函数为重载函数。

注意:形参中顶层const参数和普通参数无法区分开来。

const_cast和重载

 对于一般设计的引用参数,不需要修改实参值时,我们会使用顶层const限制形参。这时我们可以使用const_cast(去const)进行重载。

const string &shorterstring(const string &str1, const string &str2)
{
    return s1.size() <= s2.size() ? s1 : s2;
}

string &shorterstring(string &str1, string &str2)
{
    auto &r = shorterstring(str1, str2);
    return const_cast<string &>(r);
}

 函数匹配

 在函数调用时,会对各重载函数进行对比,并关联起最优的一个函数,这个过程叫做函数匹配。具体匹配过程在函数匹配章节讲到。

特殊用途语言特性

1.默认实参

 再设计函数时,有些参数在大部分情况下都是一个值,而只有少数情况才会赋为其他值,我们就可以在声明时将其赋值,这样的在声明时赋值的参数叫做默认参数。

默认参数与在调用函数时若对其不赋值,则使用默认参数的值,若对其赋值,则使用调用时的值。

由于默认参数可以在函数调用时可以赋值也可以不赋值,所以如果将其放在形参列表的中间位置会造成歧义,所以规定,默认实参后不允许有非默认参数。

因为函数可以有多个声明,所以对于同一个函数有多个声明时,需要注意在给定作用域内,一个形参只能被赋予一次默认实参。

2.内联函数和constexpr函数

 内联函数

 对于规模较小,使用次数较多的函数或者一段表达式可以写成内联函数的方式。内联函数通常就是在调用点"内联的"展开,所以相对于普通的函数调用,速度更快、运行开销更小;同样的作为一个函数比一段表达式更美观、简洁。

内联函数定义在函数返回类型前加上inline关键字即可。

constexpr函数

 是指可以用于常量表达式的函数。(是内联函数的一种)与普通函数定义类似,不过需要注意几点:

  • 函数返回类型及所有形参类型都是字面值类型
  • 函数体中只能有一条return语句

 此外,由于内联函数和constexpr函数可以定义多次,而且因为会获取其内容内容的关系仅用头文件中的声明是不够的,所以一般把这两个函数放在头文件中。

函数匹配

 候选函数:与调用函数同名,且在调用函数处可见的函数。

可行函数:候选函数中形参数目相同,且各形参与调用函数的实参类型相同或可以转换的函数。

最佳匹配:与调用函数最接近的函数,基本思想是实参类型与形参类型越接近,匹配的越好。如果匹配成功应满足以下条件

  • 该函数的每个实参的匹配不劣于其他可行函数的匹配
  • 该函数至少有一个实参的匹配优于其他可行函数的匹配

1.实参类型转换

 实参到形参的匹配过程分为几个等级:

  1. 精确匹配,分为以下几种情况:实参类型与形参类型相同;实参从数组或函数类型转为对应指针类型;实参中添加顶层const或形参中删除顶层const
  2. 通过const转换实现的匹配
  3. 通过类型提升实现的匹配
  4. 通过算术转换实现的匹配
  5. 通过类类型转换实现的匹配

函数指针

函数指针指向的是函数而非对象。函数的类型由返回类型和形参类型决定,与函数名无关。如

bool lenthCompare(const string&, const string &);

类型就是去掉函数名,想要声明指向该函数的指针,将函数名替换为指针就行。

bool (*p)(const string&, const string &);

 使用函数指针

 当把函数名作为一个值使用时,会自动转换为指针。

当使用指向函数的指针时,不用解引用。下面三种调用等价:

bool b1 = pf("hello", "goodbyte");
bool b2 = (*pf)("hello", "goodbyte");
bool b3 = lengthCompare("hello", "goodbyte");

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值