C++证道之路第八章函数探幽

本文详细讲解了C++中的内联函数、引用变量(包括const引用)、函数模板及其重载、参数传递策略等内容,强调了内存使用、效率提升和模板在通用编程中的作用。
摘要由CSDN通过智能技术生成

一、内联函数

常规函数和内联函数之间的主要区别不在于编写方式,而在于C++编译器如何将它们组合到程序中。

内联函数的编译代码与其他程序的代码“内联”起来了。也就是说,编译器将使用相应的函数代码替换函数调用。对于内敛代码,程序无须跳到另一个位置处执行代码,再跳回来。

因此,内联函数的运行速度比常规函数稍快,但代价是需要占用更多的内存。

要使用这项特性,

在函数定以前加上关键字inline;

通常的做法是省略原型,将整个定义(即函数头和所有函数代码)放在本应提供原型的地方。

内联函数不能递归

内联与宏

inline是C++新增的特性。C语言使用预处理器语句#define来提供宏——内联代码的原始实现。

二、引用变量

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

C和C++使用&符号来指示变量的地址。C++给&符号赋予了另一个含义,将其用来声明引用。

举例:

int a;
int & a = b;

这里&不是取地址运算符,而是类型标识符的一部分。

引用看上去很像伪装表示的指针(其中,*解除引用运算符被隐式理解)。实际上,引用还是不通与指针的。除了表示法不同外,还有其他的差别。例如,差别之一是,必须在声明引用时将其初始化,而不能像指针那样,先声明,再赋值。

注意:必须在声明引用变量时进行初始化。

引用更接近const指针,必须在创建时进行初始化,一旦与某个变量关联起来,就将一直效忠于它。

也就是说:

int & a = b;
//它实际上是下面代码的伪装表达式
int * const ptr = &a;

引用经常被用作函数参数,使得函数中的变量名称为调用程序中的变量的别名。

这种传递参数的方法成为按引用从传递。按引用传递允许被调用的函数能够访问调用函数中的变量。C++新增的这项特性是对C语言的超越,C语言只能按值传递。

当然,C语言也可以避开按值传递的限制,采用按指针传递的方式。

如果程序员的意图是让函数使用传递给它的信息,而不对这些信息进行修改,同时又想使用引用,则应该使用常量引用。

临时变量,引用参数和const

如果实参与引用参数不匹配,C++将生成临时变量。当前仅当参数为const引用时,C++才允许这样做,但以前不是这样的。下面看看这种情况下,C++将生成临时变量,以及为何对const引用的限制是合理的。

首先,什么时候创建临时变量呢?如果引用参数是const,则编译器将在下面两种情况下生成临时变量:

实参的类型正确,但不是左值。

实参的类型不正确,但可以转换为正确的类型。

左值是什么呢?

左值参数是可被引用的的数据对象,例如,变量,数组元素,结构成员,引用和解除引用的指针都是左值。

非左值包括字面常量(用括号括起的字符串除外,它们由其地址表示)和包含多项的表达式。

注意:如果函数调用的参数不是左值或与之相应的const引用参数的类型不匹配,则C++将创建类型正确的匿名变量,将函数调用的参数的值传递给该匿名变量,并让参数来引用该变量。

应尽可能使用const

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

使用const可以避免无意中修改数据的编程错误;

使用const是函数能够处理const和非const实参,否则将只能接受非const数据;

使用const引用使函数能够正确生成并使用临时变量;

C++11新增了另一种引用——右值引用。这种引用可指向右值,是使用&&声明的。

后面我会教你们怎么使用。

引用非常适合用于结构和类,确实,引入引用主要是为了用于这些类型的,而不是基本的内置类型。

注意:返回引用的函数实际上是被引用的变量的别名。

返回引用最重要的一点是,应避免返回函数终止时不再存在的内存单元引用。

将引用用于类对象

将类对象传递给函数时,C++通常的做法是使用引用。

对象、继承和引用  

何时使用引用参数

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

程序员能够修改调用函数中的数据对象。

通过传递引用而不是整个数据对象,可以提高程序的运行速度。

  当数据对那个较大时(如结构和类对象),第二个原因最重要。这些也是使用指针参数的原因。这是有道理的,因为引用参数实际上是基于指针的代码的另一个接口。那么什么时候应该使用引用,什么时候应该使用指针呢?

  下面是一些指导原则:

  对于使用传递的值而不做修改的函数。

  如果数据对象很小,如内置数据类型或小型结构,则按值传递。

  如果数据对象是数组,则使用指针,因为这是唯一的选择,并将指针声明为指向const的指针。

  如果数据对象是较大的结构,则使用const指针或const引用,以提高程序的效率。这样可以节省复制结构所需的时间和空间。

  如果数据对那个是类对象,则使用const引用。类设计的语义尝尝要求使用引用,这是C++新增这项特性的主要原因。因此,传递类对象参数的标准方式是按引用传递。

  对于修改调用函数中数据的函数:

  如果数据对象是内置数据类型,则使用指针。如果看到注入fixit(&x)这样的代码(其中x是int),则很明显,该函数将修改x。

  如果数据对象是数组,则只能使用指针。

  如果数据对象是结构,则使用引用或指针。

  如果数据对象是类对象,则使用引用。

  默认参数

默认参数指的是当函数调用中省略了实参时自动使用的一个值。

  函数重载

  函数多态是C++在C语言的基础上新增的功能,默认参数让您能够使用不同数目的参数调用同一个函数。而函数多态(函数重载)让您能够使用多个同名的函数。

  术语“多态”指的是有多种形式,因此函数多态允许函数可以有多种形式。

  类似的,术语“函数重载”指的是可以有多个同名的函数,因此对名称进行了重载。

  这两个术语指的是一回事。

  函数重载的关键是函数的参数列表——也称为函数特征标

  如果两个函数的参数数目和类型相同,同时参数的排列顺序也相同,则它们的特征标相同,而变量名是无关紧要的。C++允许定义名称相同的函数,条件是它们的特征标不同。

  重载引用参数

  类设计和    STL经常使用引用参数,因此直到不同引用类型的重载很有用。

  何时使用函数重载

  虽然函数重载很吸引人,但也不要滥用,进当函数基本上执行相同的任务,但使用不同形式的数据时,才应采用函数重载。

  什么是名称修饰

  C++如何跟踪每一个重载函数呢?它给这些函数指定了私密身份。使用C++开发工具中的编辑器编写和编译程序时,C++编译器将执行一些神奇的操作——名称修饰或名称矫正。它根据函数原型中指定的形参来对每个函数名进行加密。

  五、函数模板

  现在的C++编译器实现了C++新增的一项特性——函数模板。函数模板是通用的函数描述,也就是说,它们使用泛型来定义函数,其中的泛型可用具体的类型,(如int或double)替换。通过将类型作为参数传递给模板,可使编译器生成该类型的函数。由于模板允许以泛型(而不是具体类型)的方式便携程序,因此有时也被称为通用编程。
提示:

  如果需要多个将同一种算法用于不同类型的函数,请使用模板。如果不考虑向后金融的问题,并愿意键入较长的单词,则声明变量类型参数时,应使用关键字typename而不是用class。
重载的模板

  需要多个对不同类型使用同一种算法的函数时,可使用模板。

  然而并非所有的函数类型都使用相同的算法,为满足这种需求,可以像重载常规函数定义那样重载模板定义。和常规重载一样,被重载的模板的函数特征标必须不同。
  模板的局限性

  编写的模板函数很可能无法处理某些类型,另一方面,有时候通用化是有意义的,但C++语法不允许这样做。一种解决方案是,C++允许重载运算符,以便能够将其用于特定的结构或类。(运算符重载,我会在后面介绍)。另一种解决防范是,为特定类型提供具体化的模板定义。

  显式具体化。
C++98规定。

  对于给定的函数名,可以有 非模板函数,模板函数和显式具体化模板函数以及它们的重载版本。

  显式具体化的运行和定义应以template<>打头,并通过名称来指出类型。

  具体化优先于常规模板,而非模板函数优先于具体化和常规函数。
  实例化和具体化

在代码中包含函数模板本身并不会生成函数定义,它只是一个用于声明函数定义的方案
  编译器使用模板为特定类型生成函数定义时,得到的是模板实例。

模板并非函数定义,但使用int的模板实例是函数定义,这种实例化方式被称为隐式实例化

最初编译器只能通过隐式实例化,来使用模板生成函数定义,但现在C++海允许显式实例化。这意味着可以直接命令编译器穿件特定的实例,如Swap<int>()。其语法是,声明所需的种类——用<>指示类型,并在声明前加上关键字template:

警告:试图在同一个文件(或转换单元)中使用同一种类型的显式实例和显式具体化将出错。

隐式实例化,显式实例化,显示具体化,统称为具体化。它们的相同之处在于,它们表示的都是使用具体类型的函数定义,而不是通用描述。

  • 51
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值