设为首页 加入收藏

TOP

第8章 函数探幽(一)
2023-07-23 13:32:38 】 浏览:148
Tags:

说明

看《C++ Primer Plus》时整理的学习笔记,部分内容完全摘抄自《C++ Primer Plus》(第6版)中文版,Stephen Prata 著,张海龙 袁国忠译,人民邮电出版社。只做学习记录用途。

本章介绍 C++ 函数在 C 语言基础上新增的特性。

8.1 C++ 内联函数

内联函数是 C++ 为提高程序运行速度所做的一项改进,常规函数和内联函数的主要区别在于 C++ 编译器如何将它们组合到程序中。

8.1.1 内联函数原理及用法

调用常规函数时,程序将存储调用指令的内存地址,并将函数参数复制到指定的内存块中,然后跳到被调用函数的起始内存地址,执行被调用函数的代码,若有返回值,则会将返回值复制到另一指定的内存块中,最后跳回调用指令的内存地址,来回跳跃并记录跳跃位置意味着使用常规函数需要一定的开销。

使用内联函数后,编译器将自动用被调用函数的代码替换函数调用指令,此时程序无需跳到另一个地址处执行代码,再跳回来,因此,内联函数的运行速度比常规函数稍快,但代价是需要占用更多内存。(若有 10 个地方调用了同一个内联函数,则编译完成后程序将有 10 个该函数代码的副本)

使用内联函数,需采取以下两个措施之一:

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

通常的做法是省略函数原型,将加上关键字 inline 的函数定义放在本应提供函数原型的地方。

#include <iostream>

//定义内联函数
inline double square(double x) { return x * x;}

//使用内联函数
int main()
{
    std::cout << square(5.6);
    
    return 0;
}

8.1.2 内联函数与 C 宏

C 语言使用预处理器语句 #define 来提供宏,它在部分情况下可以达到和 C++ 内联函数 inline 类似的效果,但使用 C 宏来提供内联函数是一种不推荐的做法,因为它可能无法按期望运行。例如下面是一个计算平方的 C 宏,相比于 C++ 内联函数,它是通过文本替换的方式来实现内联,无法按值传递参数,很多情况下的运行结果不符合预期。

//用于计算平方的C宏
#define SQUARE(X) X*X

//使用场景一:符合预期
a = SQUARE(5.0);   //实际结果为a=5.0*5.0=25

//使用场景二:不符合预期
b = SQUARE(1+2);   //实际结果为b=1+2*1+2=5

//使用场景三:不符合预期,c实际自增了两次
c = 1;
d = SQUARE(c++);   //实际结果为d=c++*c++=1,同时c=3

8.1.3 何时使用内联函数

使用内联函数时,关键字 inline 只是程序员给编译器的一个编译建议,编译器并不一定会满足这种要求,比如函数过大或者出现了递归内联函数(内联函数不能递归),除此之外,编译器实际是否采用内联建议还与其自身的优化机制有关,比如在 Microsoft Visual Studio 下,若项目属性中未开启内联函数扩展,则不会启用内联函数的功能,此时内联函数和常规函数的调用过程没有区别。

当函数代码执行时间很短且函数频繁被调用时,可使用内联函数,此时因调用机制节省下来的时间将十分可观。

8.2 引用变量

相比于 C 语言,C++ 新增了一种复合类型:引用变量,引用是已定义的变量的别名(另一个名称)。后来 C++11 又新增了另一种引用:右值引用,这种引用可指向右值,以前的 C++ 引用现被称为左值引用

8.2.1 创建左值引用变量

引用变量可按如下方式创建,声明语句中的 & 并不是地址运算符,而是类型标识符的一部分。初始化完毕后,名称 xrx 表示同一内存单元,因而修改 rx 的值也即是修改 x 值,在之后的任一时刻,它们表示的值都相同。

//创建引用变量
int x = 101;
int & rx = x;

//查看地址(32位系统)
cout << &x;  //结果为0x012FFF08
cout << &rx; //结果为0x012FFF08

//修改引用变量会影响原始变量
rx = 555;
cout << rx;  //结果为555
cout << x;   //结果为555

左值引用的表现与指针常量很相似,它们都必须在创建的同时进行初始化,左值引用变量一旦与某个变量关联起来,就将一直效忠于它,不可再将其用作其它变量的引用,例如左值引用类型 int & 的表现与指针类型 int * const 很相似(关于 const 关键字与一级指针,可参考本人另一篇博客 C++ 一级指针与 const 关键字)。将 const 关键字用于左值引用变量时,会在以下两种情况下生成临时变量,此时左值引用变量与原始变量并不表示同一内存单元:

  • 赋值数据的类型正确,但不是左值(左值例如变量、数组元素、结构成员、引用、解除引用的指针,非左值例如字面常量、多项表达式、函数返回值);
  • 赋值数据的类型不正确,但可以转换为正确的类型。

关于 const 关键字与左值引用,可参考本人另一篇博客 C++ 左值引用与 const 关键字

8.2.2 创建右值引用变量

C++11 新增了另一种引用:右值引用(rvalue reference),这种引用可指向右值,是使用 && 声明的,也必须在创建的同时进行初始化

//创建右值引用变量
int && rrx = 55;

//查看地址(32位系统)
cout << &rrx;  //结果为0x0062FF00

//修改右值引用变量
rrx = 89;
cout << rrx;   //结果为89

右值引用一般被用来实现移动语义完美转发,这将在后续章节介绍。右值引用在部分情况下会生成临时变量(一个典型例子是使用字面常量右值如 55 来初始化右值引用变量),然后将右值引用变量作为该临时变量的别名,这与 const 左值引用十分相似,但与之不同的是:const 左值引用变量初始化完成后其值就无法被修改(权限为只读),右值引用变量初始化完成后其值仍可修改(权限为可读可写)。在另一些情况下,右值引用可以延长已有临时变量的生命周期,减少复制操作的次数(一个典型例子是使用函数返回的类对象来初始化

首页 上一页 1 2 3 4 5 6 7 下一页 尾页 1/7/7
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇c++对象模型 成员 下一篇驱动开发:内核枚举LoadImage映像..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目