C++ 函数



函数包括以下几部分:返回类型,函数名字、形参列表。

函数的调用完成两项工作:

一、是用实参初始化函数对应的形参;

二、是将控制权转移给被调函数。

当调用一条return语句时函数结束执行过程时,也完成两项工作:

  1. 返回return语句中的值;

  2. 将控制权从被调函数转移回主调函数。

     

    有些时候,有必要令局部变量的生命周期贯穿函数调用及之后的时间。由于局部对象对函数内对象生命周期有限制,所以可以使用局部静态对象,将局部变量定义成static类型从而获得贯穿函数调用及之后时间的对象。

    局部静态对象,在程序的执行路径第一次经过对象定义语句时初始化,并且直到程序终止才会被撤销,函数的结束执行对其不会有影响。

     

    函数的名字也必须在使用之前声明。函数的定义只能定义一次,但可以声明多次(函数的声明无需函数体)

    对于函数的声明建议在头文件中进行,在源文件中定义。在头文件中声明函数能够确保同一函数的所有声明保持一致,如果想改某一个接口,只需需要改变一条声明即可。

     

    分离式编程:随着程序越来越复杂,希望将程序的各个部分分别存储在不同文件中。例如:将函数放到一个程序中,函数声明放到头文件中,主函数放到另一个函数中。函数中应该包含函数声明的头文件。

     

    参数传递:

  1. 引用传递:当形参是引用类型时,它对应的实参被引用传递。作用在引用所引的对象上,对变量的改动会影响初始值。

  2. 值传递:当实参的值被拷贝给形参时,形参和实参是两个相互独立的对象。(对变量的改动不会影响初始值)。值传递还有一种是指针形参,他传递的是对象的地址,可以改变指针所指的值,但是不会改变传递给形参的地址本身。(指针的传递是不被推荐的,如果要改变传递变量的值,建议使用引用传递)。

    值传递,拷贝大的类类型对象或容器对象比较低效,并且有的类类型不支持拷贝操作。当某种类型不支持拷贝操作时,函数只能通过引用形参访问该类型的对象。(如果函数无须改变引用形参的值,最好将其声明为常量引用)

     

    使用引用形参返回额外的信息:

    一个函数只能返回一个值,然而有时函数需要同时返回多个值,引用形参为返回多个结果提供了有效的途径。

    返回多个值得方法,一、定义一个保存多个变量的新类型,二、通过引用类型修改主调函数中已经定义的变量。

     

    const形参和实参:

    const总结:const对象称之为常量,它的值不能改变。因为const对象一旦创建就不能改变,所以需要对其必须进行初始化。对const对象的限定是只能在const类型的对象上执行不改变其内容的操作。在const对象的初始化时可以使用常量对象对其初始化,也可以使用非常量对象对其进行初始化(const的常量特性仅仅在执行改变const对象的操作时才发挥作用,拷贝一个对象的值并不会对它参数影响)

    默认情况下,const对象被设定为仅在文件内有效,当多个文件中出现了同名的const变量时,其实等同于在不同文件中分别定义独立的变量。

    还有一种情况,const不是常量表达式,但又必须在文件中共享。这时解决的办法是对于const变量不管是声明还是定义都添加extern关键字。例如:extern const int bufsize = fcn();

    const的应用,称之为对常量的引用。与普通引用不同的是,对常量的引用不能被用作修改它所绑定的对象。

    指针和const,指向常量的指针,不能用于改变指针所指对象的值,要想存放常量对象的地址只能使用指向常量的指针。也成为底层const

    const指针,将指针本身定为常量,既不变的是指针本身的值而非指向的那个值。也称为顶层const,但顶层const并不局限于指针,顶层const作用于对象本身。如:const int ci = 42;ci同样也是顶层cosnt

     

    在函数形参中建议使用常量引用,将形参定义为一种普通引用是一种比较常见的错误。这样做会带给函数调用者一种误导,即函数可以修改它的值。此外,使用普通引用会极大的限制函数所能接受的实参类型。

     

    数组形参:由于数组的两个性质(1、不允许拷贝数组,2、使用数组时会将其转换成指针)。

    所以当我们为函数传递一个数组时,实际上传递的是指向数组首元素的指针。那么为了使在函数中对数组的使用不越界,就需要为函数提供数组确切尺寸的额外信息。管理指针形参有三种常用的技术:

  1. 使用标记指定数组的长度(有明显结束标记,但不会与普通数据混淆),例如:字符串末尾有空字符。

  2. 传递指向数组首元素和尾后元素的指针(向函数传递两个指针)。

  3. 显式传递一个表示数组大小的形参,定义一个专门表示数组大小的形参。

     

    main函数命令行选项,给主函数传递参数。

    int main(int argc, char *argv[]){ ... }

    第一个形参argc表示数组中字符串的数量,第二个形参argv是一个数组(它的元素是指向C风格字符串的指针)。当实参传给main函数后,argv的第一个元素指向程序的名字或者一个空字符串,接下来的元素依次传递命令行提供的实参。

     

    含有可变形参的函数:如果所有的实参类型相同,可以传递一个名为initializer_list的标准库类型;如果实参的类型不同,可以编写一种特殊的函数(可变参数模板)。

    如果函数的实参数量未知但是全部实参的类型都相同,可以使用initializer_list类型的形参。用于表示某种特定类型的值的数组。Initializer_list类型定义在同名的头文件中。Initializer_list是一个模板类型,并且其中的值不能改变。如果想向initializer_list形参中传递一个值的序列,则必须把序列放在一对花括号中。

    省略符形参:是为了方便C++程序访问某些特殊的C代码而设置的。这些代码使用了名为varargsC标准库功能。省略符形参只能出现在形参列表的最后一个位置。

     

    return语句的两种形式:

  1. return;没有返回值的return语句只能用在返回类型是void的函数中。返回void的函数不要求非得有return语句。因为这类函数的最后一句后面会隐式地执行return。如果强行令void函数返回其他类型的表达式将产生编译错误。

  2. return expression

    不要返回局部对象的引用和指针,因为函数调用完成后,变量所占的空间也随之被释放。因此引用和指针将不再指向有效的内存区域。

     

    列表初始化返回值:函数可以返回花括号包围的值的列表。如果列表非空,临时值执行值得初始化;否则,返回的值由函数的返回类型决定。例如:{functionX”,“expected}

     

    主函数main的返回值,如果函数的返回类型不是void,那么它必须返回一个值,但是对于main函数允许没有return语句直接结束。编译器将隐式地插入一条返回0return语句。

     

    返回数组指针:因为数组不能拷贝,所以函数不能返回数组。不过函数可以返回数组的指针或引用。但定义一个返回数组的指针或引用的函数比较烦琐,所以(1)最直接的方法是使用类型别名。

    例如:method one: typedef int arrT[10];

          method two: using arrT = int[10];

         arrT* func(int i);

    2)声明一个返回数组指针的函数:(不使用别名的情况下,但是必须牢记名字后面数组的维度)返回数组指针的函数形式如下:

    Type (*function(paramter_list))[dimension], Type元素的类型,dimension数组的大小。(*function(paramter_list))两端的括号必须存在(指明声明的是数组指针,指向数组的指针,不是数组里面存储的是指针)。例:int (*func(int i)) [10];

  1. 使用尾置返回类型:对于返回类型是数组的指针或数组的引用,尾置返回类型跟在形参列表后面并以一个->符号开头。为了表示函数真正的返回值类型,在本应该出现返回类型的地方放置一个auto: auto func(int i) -> int(*) [10];

     

    函数重载:同一作用域内的几个函数名字相同但形参列表不同。函数重载在一定程度上减轻程序员起名字、记名字的负担。main函数不能重载。返回类型的差异不能判断函数是否可以重组。

     

    默认实参:调用包含默认实参的函数时,可以包含该实参也可以省略该实参。在设计默认实参时,要合理的设置形参的顺序。尽量让不怎么使用默认值的形参出现在前面,让经常使用默认值的形参出现在后面。函数的声明可以声明一次,也可以声明多次(最好在头文件中)。但是在函数的多次声明中,后续的声明只能为之前那些没有默认值的形参添加默认值,而且该形参右侧的所有形参必须都有默认值。局部变量不能作为默认实参,表达式也可以作为默认实参,只要其能够转换成形参所需的类型。

     

    内联函数:对于一些小函数,对它们的调用一般比求等价表达式的值要慢一些,所以可以将函数保存为内联函数,将它在每个调用点上“内联地”展开。内联函数只需在函数的返回值前面加上inline即可。一般,内联机制用于优化规模较小,流程直接,频繁调用的函数。对于较大的函数不可能内联地展开。

    constexpr函数:用于常量表达式,需要遵循:函数的返回类型及所有形参的类型都得是字面值类型。函数体中都得由一条return语句。

    调试帮助:C++为程序员提供了一种类似于头文件保护的技术,以便有有选择地执行调试代码。基本思想是:程序可以包含一些用于调试的代码,但是这些代码只在开发程序时使用。当程序开发完准备发布时,要先屏蔽掉调试代码。两项预处理功能:assert/NDEBUG

    assert预处理宏:assertexpr)首先对expr求值,表达式为假,assert输出信息并终止程序的执行。如果表达式为真,assert什么也不做。

    assert定义在cassert头文件中,由预处理器管理不需要using

    assert依赖于一个名为NDEBUG的预处理变量的状态,如果定义了NDEBUGassert什么也不做,默认情况下没有定义NDEBUG,此时assert将执行运行时检查。

     

    函数指针:函数指针指向的是函数,而非对象,如果函数指针指向成功,可以使用指针调用函数。

    函数指针指向某种特定类型,函数的类型由它的返回值类型和形参类型共同决定,与函数名无关。

    例如:bool lengthCompare(const string&, const string &);

    函数的类型是bool (const string &, const string &),要声明一个可以指向该函数的指针,只需要用指针替换函数名即可。

    例如:bool (*pf) (const string&, const string &);

    可以将函数名作为一个值使用时,该函数自动地转换成指针。

    Pf = lengthCompare; / Pf = &lengthCompare;(取地址符可选)

    函数不能作为函数的形参,但是函数指针可以作为函数的形参。

     

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值