第6章 函数

6.1 函数基础
  • 调用运算符

    ( ),作用于一个表达式(函数,或者函数指针),实参初始化形参的顺序不确定

  • 自动对象

    • 当函数控制路径经过变量定义语句时,创建该对象
    • 当到达定义所在块的末尾时,销毁该对象
  • 局部静态变量

    • 第一次经过定义语句时创建
    • 直到程序终止销毁
  • 分离式编译

    //程序分为多个文件,分别独立编译
    //假设有 main.cpp / func.cpp / func.h 三个文件
    $ gcc -c main.cpp
    $ gcc -c func.cpp
    $ gcc main.o func.o -o main
    
  • 参数传递

    • 引用传递:形参为实参的别名
    • 值传递:形参和实参分别独立,不能通过形参修改实参
    • 使用引用避免拷贝:当无需修改形参时,建议使用常量引用
6.2 参数传递
  • const形参与实参

    • 当用实参初始化形参时,会忽略形参的顶层const

    • 当形参为顶层const时,传入常量对象或非常量对象都是可行的

      void func(const int i){};
      void func(int i){};
      //二者等价,若同时出现则会报错,重定义
      
  • 非常量形参引用带来的问题

    • 函数可能会修改实参的值

    • 不能使用const对象、字面值传递给普通的引用形参

      void func(int &i){};
      //调用
      func(5);	//错误
      const int a=10;
      func(a);	//错误,不能把普通引用捆绑到const对象上
      
  • 数组形参

    • 数组不允许拷贝(所以不能以值传递数组)

    • 使用数组时,通常会将其转为指针

      void p(const int*);
      //下面两者等价于前面
      void p(const int[]);
      void p(const int[10]);		//10并没有限制作用,只是一个期望值
      
    • 数组引用&数组指针形参

      void p(int (&arr)[10]);		//10是类型的一部分
      //传递多为数组,下面二者等价
      void p(int (*arr)[10]);
      void p(int arr[][10]);
      
      
  • 可变形参

    • 如果所有的实参类型相同,则可以传递一个名为initializer_list的标准库类型
    • 类型不同,使用可变参数模板(此处没有细讲)
    • 使用省略符形参
    //initializer_list
    //传递值得序列,将其放入{}内
    initializer_list lst2(lst);		//不拷贝lst中得元素,共享内容
    //initializer_list的元素永远是常量,不能改变元素的值
    
    //省略符形参,只能出现在最后
    void func(parmater-list,...);	//省略部分无需类型检查
    
6.3 返回值
  • 有返回值函数

    • 返回值用于初始化调用点的一个临时量,该临时量为函数调用结果

    • 不要返回局部变量的引用和指针

    • 列表初始化返回值

      vector<string> p()
      {
          return {"fun","okey"};
      }
      
    • main 函数的返回值,可以使用机器无关的EXIT_FAILURE EXIT_SUCCESS

  • 返回数组指针

    • 采用类型别名

      using arrT=int[10];
      arrT* func(int i);
      
    • 返回数组指针

      //如果想定义一个返回数组指针的函数,数组的维度必须在函数名后面
      //格式
      Type (*func(paramter-list))[dimension];
      //中间的圆括号必须存在,否则返回类型就变成了指针数组,不合法
      int (*func(int i))[10];
      //由内向外解释
      func(int i);	//调用该函数需要一个int类型参数
      (*func(int i));	//意味着函数调用结果可以解引用
      (*func(int i))[10];	//解引用结果得到一个大小为10的数组
      int (*func(int i))[10];	//其类型为int
      
    • 尾置返回类型

      auto func(int i)->int(*)[10];
      
    • 使用decltype

      int odd[]={1,3,5,7,9};
      decltype(odd) *arrPtr(int i);
      //注意加 *
      
6.4 函数重载
  • 重载与const形参

    //顶层const形参不影响传入参数的对象
    Record lookup(Phone);
    //等价于
    Record lookup(const Phone);
    
  • 底层const形参保留

    Record lookup(Account&);
    Record lookup(const Account&);	//与前者不同,重载
    
  • 默认实参

    //默认实参一般放在参数列表的后面
    string screen(string words,int width=100,int height=300);
    //函数的后续声明只能为之前那些没有默认值的形参添加默认实参
    string screen(sz,sz,char=' ');
    string screen(sz,sz,char='*');	//错误,重复声明
    string screen(sz=24,sz=80,char);	//正确重载,添加默认参数,注意之前的默认参数无需再写出来
    
  • 函数匹配

    • 找到函数名相同的候选函数
    • 找到能使用指定实参调用的可行函数(形参数量与实参类型相同或者能够转换)
    • 最佳匹配
      • 该函数的每个实参的匹配都不劣于其他可行函数需要的匹配
      • 至少有一个实参的匹配由于其他可行函数提供的匹配
      • 若存在二义性,则会报错
6.5 调试与运行的一些操作
  • 内联

    通过加上inline关键字,再调试时,函数会自动展开,适用于规模小、流程直接、使用频繁的函数

  • assert & NDEBUG

    assert (expr);
    //expr为假,输出信息并终止程序
    //expr为真,什么都不做
    //assert的行为依赖于NDEBUG的状态
    - 定义了NDEBUG,什么也不做
    - 未定义NDEBUG,执行运行时检查
    
  • 用NDEBUG编写条件调试代码

    void print(int i)
    {
        #ifndef NDEBUG
        	//输出调试信息
        #endif
    }
    
  • 预处理器用于调试的名字

    __func__		//存放当前调试函数的名字
    __FILE__		//存放当前文件名
    __LINE__		//当前行号
    __TIME__		//文件编译时间
    __DATE__		//文件编译日期
    
6.6 函数指针
  • 函数的类型

    //由返回类型和形参类型共同决定
    //若要声明函数指针,只需用指针替换函数名
    bool lengthCompare(const string&,const string&);
    //函数指针
    bool (*pf)(const string&,const string&);
    pf=lengthCompare;	
    pf=&lengthCompare;
    //二者都可行
    
    //可以直接使用函数指针调用函数,并且无需提前解引用
    bool b1=pf("aaa","bbb");
    bool b2=(*pf)("aaa","bbb");		//先解引用,再调用
    
  • 函数指针作形参

    //是函数类型,但是会自动转为指针
    void useBigger(string a,string b,bool pf(const string &,const string&));	
    //直接使用指针类型
    void useBigger(string a,string b,bool (*pf)(const string &,const string&));
    //使用时,可以直接使用函数作为实参,会自动转为指针
    useBigger(A,B,lengthCompare);
    
  • 返回函数指针

    • 使用别名

      using F=int(int*,int);		//F是函数类型
      using PF=int(int*int);		//PF:函数指针
      //返回类型不会自动将函数类型转为指针,必须显式指定
      
    • 直接声明

      int (*fun(int))(int*,int);
      //由内向外解释
      //fun有参数列表,所以fun是一个函数,前面有*,则其返回的是一个指针,指针本身也包含参数列表,故其指向一个函数,该函数的返回类型是int
      
    • 使用尾置类型

      auto fun(int)->int(*)(int*,int);
      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值