C++ Primer Plus 学习笔记(第 8 章 函数探幽)

C++ Primer Plus 第 8 章详细介绍了函数的各种特性,包括内联函数以提高运行速度,引用变量提供按引用传递参数的能力,以及函数模板实现泛型编程。此外,章节还涵盖了默认参数、函数重载和模板的使用策略,如何时使用引用参数、函数模板的具体化等。内联函数通过避免函数调用的开销来提高效率,而引用作为参数可以修改原始数据。函数模板则允许编写通用的函数,能够处理不同类型的参数。章节末尾总结了如何利用这些特性优化代码和提高程序性能。
摘要由CSDN通过智能技术生成

C++ Primer Plus 学习笔记

第 8 章 函数探幽

内联函数

编译过程的最终产品是可执行程序 —— 由一组机器语言指令组成。运行程序时,操作系统将这些指令载入到计算机在内中,因此每条指令都有特定的内存地址。执行到函数调用指令时,程序将在函数调用后立即存储该指令的内存地址,并将函数参数复制到堆栈(为此保留的内存块),跳到标记函数起点的内存单元,执行函数代码(也许还需将返回值放入到寄存器中),然后跳回到地址被保存的指令处(这与阅读文章时停下来看脚注,并在阅读完脚注后返回到以前阅读的地方类似)。来回跳跃并记录跳跃位置意味着以前使用函数时,需要一定的开销。
C++ 内联函数提供了另一个选择。内联函数的编译代码与其他程序代码“内联”了起来。编译器将使用相应的函数代码替换函数调用,对于内联代码,程序无需跳到另一个位置处执行代码,再跳回来。因此,内联函数的运行速度比常规函数稍快,但代价是需要占用更多的内存。调用几次内联函数,就包含该函数代码的几个副本。
应有选择的使用内联函数。如果执行函数代码的时间比处理函数调用机制的时间长,则节省的时间将只占整个过程的很小一部分。如果代码执行时间乱短,则内联调用就可以节省非内联调用使用的大部分时间。另一方面,由于这个过程相当快,因此尽管节省了该过程的大部分时间,但节省的时间绝对值并不大,除非该函数经常被调用。
要使用这项特性,必须采取下述措施之一:

  • 在函数声明前加上关键字inline
  • 在函数定义前加上关键字inline

通常的做法是省略原型,将整个定义(即函数头和所有函数代码)放在本应提供原型的地方。
程序员请求将函数作为内联函数时,编译器并不一定满足这种要求。它可能认为该函数过大或注意到函数调用了自己(内联函数不能递归),因此不将其作为内联函数;而有些编译器没有启用或实现这种特性。
内联函数与常规函数一样,也是按值传递参数的,所以参数可以是表达式,这使得 C++ 的内联功能远远胜过 C 语言的宏定义。

引用变量

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

创建引用变量

C++ 给&符号赋予了另一个含义,将其用来声明引用。

int rats;
int & rodents = rats;   // makes rodents an alias for rats

其中,&不是地址运算符,而是类型标识符的一部分。就像声明中的char *指的是指向char的指针一样,int &指的是指向int的引用。上述引用声明允许将ratsrodents互换 —— 它们指向相同的值和内存单元。
引用看上去像伪装表示的指针(其中,*解除引用运算符被隐式理解)。实际上,引用还是不同于指针的。除了表示法不同外,还有其他的有差别。例如,差别之一是,必须在声明引用时将其初始化,而不能像指针那样,先声明,再赋值。
注意:必须在声明引用变量时进行初始化。
引用更接近const指针,必须在创建时进行初始化,一旦与某个变量关联起来,就将一直效忠于它。
可以通过初始化来设置引用,但不能通过赋值来设置。

将引用用作函数参数

引用经常被用作函数参数,使得函数中的变量名成为调用程序中的变量的别名。这种传递参数的方法称为按引用传递。按引用传递允许被调用的函数能够访问调用函数中的变量。C++ 新增的这项特性是对 C 语言的超越,C 语言只能按值传递。按值传递导致被调用函数使用调用程序的值的拷贝。C 语言也允许避开按值传递的限制,采用按指针传递的方式。
按引用传递的按值传递看起来相同,只能通过原型或函数定义才能知道是按引用传递。地址运算符&使用按地址传递一目了然。按引用传递的函数与按值传递的函数,唯一的外在区别是声明函数参数的方式不同。
传递引用的函数和传递指针的函数,第一个区别是声明函数参数的方式不同,另一个区别是需要在函数使用指针过程中使用解除引用运算符*

引用的属性和特别之处

如果实参与引用参数不匹配,C++ 将生成临时变量。当前,仅当参数为const时,C++ 才允许这样做。
如果引用参数是const,则编译器将在下面两种情况下生成临时变量:

  • 实参的类型不正确,但不是左值;
  • 实参的类型不正确,但可以转换为正确的类型。

左值参数是可被引用的数据对象,例如,变量、数组原素、结构成员、引用和解除引用的指针都是左值。非左值包括字符常量(用引号括起的字符串除外,它们由其地址表示)和包含多项的表达式。
在C 语言中,左值最初指的是可出现在赋值语句左边的实体,但引入关键字const后,常规变量和const变量都可视为左值,因为可通过地址访问它们。但常规变量属于可修改的左值,而const变量属于不可修改的左值。

double refcube(const double & ra){return ra * ra * ra;}

double side = 3.0;
double * pd = &side;
double & rd = side;
long edge = 5L;
double lens[4] = {2.0, 5.0, 10., 12.0};

double c1 = refcube(side);          // ra is side
double c2 = refcube(lens[2]);       // ra is lens[2]
double c3 = refcube(rd);            // ra is rd is side
double c4 = refcube(*pd);           // ra is *pd is side
double c5 = refcube(edge);          // ra is temporary variable
double c6 = refcube(7.0);           // ra is temporary variable
double c7 = refcube(side + 10.0);   // ra is temporary variable

参数sidelens[2]rd*pd都是有名称的、double类型的数据对象,因此可以为其创建引用。edge虽然是变量,类型却不正确,7.0side + 10.0的类型正确,但没有名称,在这些情况下,编译器都将生成一个临时匿名变量,并让ra指向它,函数调用结束后将被删除。
实际上,对于形参为const引用的 C++ 函数,如果实参不匹配,则其行为类似于按值传递,为确保原始数据不被修改,将使用临时变量来存储值。
注意:如果函数调用的参数不是左值或与相应的const引用参数的类型不匹配,则 C++ 将创建类型正确的匿名变量,将函数调用的参数的值传递给该匿名变量,并让参数来引用该变量。
将引用参数声明为常量数据的引用的理由有三个:

  • 使用const可以改免无意中修改数据的编程错误;
  • 使用const使函数能够处理const和非const实参,否则将只能接受非const数据;
  • 使用const引用使函数能够正确生成并使用临时变量。

因此,应尽可能将引用形参声明为const
C++11 新增了另一种引用 —— 右值引用。这种引用可指向右值,是使用&&声明的:

double && rref = std::sqrt(36.0);   // not allowed for double &
double j = 15.0;
double && jref = 2.0 * j + 18.5;    // not allowed for double &
std::cout << rref << '\n';          // display 6.0
std::cout << jref << '\n';          // display 48.5

新增右值引用的主要目的是,让库设计人员能够提供有些操作的更有效实现。以前的引用(使用&声明的引用)现在称为左值引用。

将引用用于结构

引用非常适合用于结构和类。引入引用主要是为了用于这些类型,而不是基本的内置类型。
使用结构引用参数的方式与使用基本变量引用相同,只需在声明结构参数时使用引用运算符&即可。
如果不希望函数修改传入的结构,可使用const

返回结构引用

传统返回机制与按值传递函数参数类似:计算关键字return后面的表达式,并将结果返回给调用函数。从概念上说,这个值被复制到一个临时位置,而调用函数将使用这个值。
如果函数返回一个结构,而不是指向结构的引用,将把整个结构复制到一个临时位置,调用函数再使用这个值。这样不如返回值为引用时的效率高。
注意:返回引用的函数实际上是被引用函数的别名。
返回引用时最重要的

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值