函数进阶

  • 内联函数
  • 引用变量
  • 默认参数
  • 函数重载
  • 函数模板
  • 总结

C++还提供了许多新的函数特性,使之有别于C语言。新特性包括内联函数、按引用传递变量、默认的参数值、函数重载(多态)以及模板函数。

内联函数

  • 内联函数的运行速度比常规函数稍快,但代价是需要占用更多内存。应有选择地使用内联函数。如果执行函数代码的时间比处理函数调用机制的时间长,则节省的时间将只占整个过程的很小一部分。如果代码执行时间很短,则内联调用就可以节省非内联调用使用的大部分时间。比如说,如果函数定义占用多行(假定没有使用冗长的标识符),则将其作为内联函数就不太合适。
  • 另外,内联函数不能递归。
  • 要使用这项特性,必须采取下述措施之一:
    1. 在函数声明前加上关键字inline;
    2. 在函数定义前加上关键字inline

引用变量

  • C++新增了一种复合类型——引用变量。引用是已定义的变量的别名(另一个名称)。通过将引用变量用作参数,函数将使用原始数据,而不是其副本。

  • 必须在声明引用时将其初始化,而不能像指针那样,先声明,再赋值。

  • 将引用参数声明为常量数据的引用的理由有三个:

    1. 使用const可以避免无意中修改数据的编程错误;
    2. 使用const使函数能够处理const和非const实参,否则将只能接受非const数据;
    3. 使用const引用使函数能够正确生成并使用临时变量。
      因此,应尽可能将引用形参声明为const。
  • 使用&声明的引用称为左值引用,C++11新增了另一种引用——右值引用(rvalue reference).

  • 返回引用时需要注意的问题:

    1. 应避免返回函数终止时不再存在的内存单元引用;
    2. 也应避免返回指向临时变量的指针(不要返回指向局部变量或临时对象的引用。函数执行完毕后,局部变量和临时对象将消失,引用将指向不存在的数据。);
    3. 为了避免上述问题,最简单的方法是,返回一个作为参数传递给函数的引用;
    4. 另一种方法是,用new来分配新的存储空间,并返回指向该内存空间的指针。这种方法存在一个问题:在不再需要new分配的的内存时,应使用delete来释放它们。但是函数调用隐藏了对new的调用,这使得以后很容易忘记使用delete来释放内存。后面要讨论的auto_ptr模板以及C++11新增的unique_ptr可帮助程序员自动完成释放工作。
  • 继承的另一个特征是,基类引用可以指向派生类对象,而无需进行强制类型转换。这种特征的一个实际结果是,可以定义一个接受基类引用作为参数的函数,调用该函数时,可以将基类对象作为参数,也可以将派生类对象作为参数。

  • 方法调用self(ios_base::fixed)将对象置于使用定点表示法的模式;self(ios_base::showpoint)将对象置于显示小数点的模式,即使小数部分为零。方法precision()指定显示多少位小数(假定对象处于定点模式下)。所有这些设置都将一直保持不变,直到再次调用相应的方法重新设置它们。方法width()设置下一次输出操作使用的字段宽度,这种设置只在显示下一个值时有效,然后将恢复到默认设置。默认的字段宽度为零,这意味着刚好能容纳下要显示的内容。

  • 使用引用参数的主要原因有两个:

    1. 程序员能够修改调用函数中的数据对象;
    2. 通过传递引用而不是整个数据对象,可以提高程序的运行速度。
  • 引用、指针、按值传递的选用指导原则:
    对于使用传递的值而不做修改的函数:

    1. 如果数据对象很小,如内置数据类型或小型结构,则按值传递;
    2. 如果数据对象是数组,则使用指针,因为这是唯一的选择,并将指针声明为指向const的指针;
    3. 如果数据对象是较大的结构,则使用const指针或const引用,以提高程序的效率。这样可以节省复制结构所需的时间和空间;
    4. 如果数据对象是类对象,则使用const引用。传递类对象参数的标准方式是按引用传递;

    对于修改调用函数中数据的函数:
    5. 如果数据对象是内置数据类型,则使用指针;
    6. 如果数据对象是数组,则只能使用指针;
    7. 如果数据对象是结构,则使用引用或指针;
    8. 如果数据对象是类对象,则使用引用。

默认参数

  • 对于带参数列表的函数,必须从右向左添加默认值。也就是说,要为某个参数设置默认值,则必须为它右边的所有参数提供默认值。实参按从左到右的顺序依次被赋给相应的形参,而不能跳过任何参数。

函数重载

  • 默认参数让您能够使用不同数目的参数调用同一个函数,而函数多态(重载)让您能够使用多个同名的函数。
  • 函数重载的关键是函数的参数列表——也称为函数特征标(function signature)。
  • 编译器在检查函数特征标时,将把类型引用和类型本身视为同一个特征标。
  • 仅当函数基本上执行相同的任务,但使用不同形式的数据时,才应使用函数重载。
  • C++如何跟踪每一个重载函数呢?它给这些函数指定了秘密身份。使用C++开发工具中的编译器编写和编译程序时,C++编译器将执行一些神奇的操作——名称修饰(name decoration)或名称矫正(name mangling),它根据函数原型中指定的形参类型对每个函数名进行加密。

函数模板

  • 如果需要多个将同一种算法用于不同类型的函数,请使用模板。如果不考虑向后兼容的问题,并愿意键入较长的单词,则声明类型参数时,应使用关键字typename而不使用class.
  • 模板的使用包括三种:隐式实例化、显式实例化、显式具体化。
  • 对于函数重载、函数模板和函数模板重载,C++需要(且有)一个定义良好的策略,来决定为函数调用使用哪一个函数定义,尤其是有多个参数时。这个过程称为重载解析(overloading resolution)。大致过程如下:
    1. 创建候选函数列表;
    2. 使用候选函数列表创建可行函数列表;
    3. 确定是否有最佳的可行函数。

总结

C++扩展了C语言的函数功能。通过将inline关键字用于函数定义,并在首次调用该函数前提供其函数定义,可以使得C++编译器将该函数视为内联函数。也就是说,编译器不是让程序跳到独立的代码段,以执行函数,而是用相应的代码替换函数调用。只有在函数很短时才能采用内联方式。

引用变量是一种伪装指针,它允许为变量创建别名(另一个名称)。引用变量主要被用作处理结构和类对象的函数的参数。通常,被声明为特定类型引用的标识符只能指向这种类型的数据;然而,如果一个类(如ofstream)是从另一个类(如ostream)派生出来的,则基类引用可以指向派生类对象。

C++原型让您能够定义参数的默认值。如果函数调用省略了相应的参数,则程序将使用默认值;如果函数调用提供了参数值,则程序将使用这个值(而不是默认值)。只能在参数列表中从右到左提供默认参数,因此,如果为某个参数提供了默认值,则必须为该参数右边所有的参数提供默认值。

函数的特征标是其参数列表。程序员可以定义两个同名函数,只要其特征标不同。这被称为函数多态或函数重载。通常,通过重载函数来为不同的数据类型提供相同的服务。

函数模板自动完成重载函数的过程。只需使用泛型和具体算法来定义函数,编译器将为程序中使用的特定参数类型生成正确的函数定义。

C++ Primer Plus学习(八)——函数进阶相关推荐

  1. Python之路---函数进阶

    程序员三大美德: 懒惰 因为一直致力于减少工作的总工作量. 很多人学习python,不知道从何学起. 很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手. 很多已经做案例的人,却不知 ...

  2. python 函数进阶_Python学习入门基础:一篇文章搞定函数基础、函数进阶

    一.函数基础函数的快速体验 函数的基本使用 函数的参数 函数的返回值 函数的嵌套调用 在模块中定义函数私信小编001即可获取Python学习资料01. 函数的快速体验 1.1 快速体验 所谓函数,就是 ...

  3. Python学习入门基础:一篇文章搞定函数基础、函数进阶

    一.函数基础 函数的快速体验 函数的基本使用 函数的参数 函数的返回值 函数的嵌套调用 在模块中定义函数 很多人学习python,不知道从何学起. 很多人学习python,掌握了基本语法过后,不知道在 ...

  4. 带你学习javascript的函数进阶(二)

    上一篇文章分享了<带你学习Javascript中的函数进阶(一)>,今天继续学习javascript的函数进阶的内容. 文章目录 1 严格模式 1.1 什么是严格模式 1.2 开启严格模式 ...

  5. JS进阶学习(作用域、函数进阶、解构赋值、原型链)

    文章目录 1.面相对象编程介绍 2.ES6中的类和对象 3.类的继承 ES6中的类和对象 三个注意点 作用域 局部作用域 全局作用域 作用域链 JS垃圾回收机制(GC) JS垃圾回收机制-算法说明 闭 ...

  6. Python基础学习(七)--函数进阶,全局局部,global,nonlocal,enclosing,命名空间,作用域,重要函数,lambda,闭包

    函数进阶 一.函数参数类型 可变类型参数与不可变类型参数 不可变类型参数:数字.字符串.元组 可变类型参数:列表.字典.集合 (1)不可变类型参数 fun(a)–内部修改a的值,只是修改了一个对象的副 ...

  7. Python学习笔记---day12函数进阶

    day12函数进阶 函数的嵌套 闭包 装饰器 上述内容均属于函数部分必备知识,以后开发时直接和间接都会使用,请务必理解(重在理解,不要去死记硬背). 1. 函数嵌套 Python中以函数为作用域,在作 ...

  8. JS进阶 Day1 作用域 函数进阶 结构赋值(学习笔记)

    1.作用域 1)局部作用域 函数作用域 注:函数执行完毕后,函数内部的变量实际被清空了 块级作用域 在js中使用{}包裹的代码称为代码块,代码块内部声明的变量外部将{有可能}无法访问 let声明的变量 ...

  9. Python学习day13-函数进阶(1)

    Python学习day13-函数进阶(1) 闭包函数 闭包函数,从名字理解,闭即是关闭,也就是说把一个函数整个包起来.正规点说就是指函数内部的函数对外部作用域而非全局作用域的引用. 为函数传参的方式有 ...

最新文章

  1. 《C与指针》第七章练习
  2. mongo connections url string 的问题
  3. 【Windows部署】首次安装的谷歌Chrome浏览器出现【无法打开此页面】问题处理(详细图文步骤)
  4. 【计算几何】【预处理】【枚举】Urozero Autumn Training Camp 2016 Day 5: NWERC-2016 Problem K. Kiwi Trees...
  5. UVa 11136 - Hoax or what
  6. spring框架做全局异常捕获_@ControllerAdvice注解(全局异常捕获)
  7. dubbo中使用kryo进行对象序列化,反序列化时报错
  8. 不必仰望他人,用自己的方式活着就好
  9. Monkey命令参数详解
  10. 《工业设计史》第十章:战后重建与设计
  11. 全志A31S源码编译
  12. Pytorch之反向传播
  13. 3DMAX 切换视图+切换到摄像机视角
  14. 【Python】10行代码获取海贼王最新目录
  15. 《Docker》高级篇
  16. 我是如何揭穿“娱乐圈”大佬
  17. 苏州企业所得税汇算清缴十大风险点(上)
  18. 编译原理复习(4)语法分析--自上而下分析
  19. 云服务器上通过wget安装JDK
  20. 《30天自制操作系统》-day0(MAC)

热门文章

  1. C++bitset二进制有序集
  2. opencv 霍夫变换检测直线和圆
  3. Java 图片验证码的实现和模拟简单的登录
  4. javascript学习之利用DOM和正则表达式判断主流浏览器的类型
  5. C++中实现精度的控制和输出 showpoint<<或者fixed<<setprecision()用法
  6. paper reading:Part-based Graph Convolutional Network for Action Recognition
  7. zedboard连接pmod oledrgb
  8. vivado2018.3和modelsim10.6d进行联合仿真
  9. 深入理解C++ new/delete, new []/delete[]动态内存管理
  10. wtforms Form实例化流程(源码解析)