《C++ Primer Plus》读书笔记之六—函数探幽
第八章 函数探幽
1、常规函数与内联函数的主要区别不在于编写方式,而在于C++编译器如何将它们组合到程序中。
2、常规函数调用使程序跳到另外一个地址(函数地址),并在函数结束时返回,更详细的的实现过程:执行到函数调用指令时,程序将在函数调用后立即存储该指令的内存地址,并将函数参数复制到堆栈(为此保留的内存块),跳到标记函数起点的内存单元,执行函数代码(也许还需将返回值i放入寄存器)然后跳回到地址被保存的指令处。来回跳跃并记录跳跃位置意味着以前使用函数时,需要一定的开销。
3、内联函数:编译器将使用相应的函数代码替换函数调用。对于内联代码,程序无需跳到另一个位置处执行代码,然后再跳回来。因此,内联函数的运行速度比常规函数稍快,但代价是需要占用更多的内存。
4、要使用内联函数,必须采取下述措施之一:①再函数声明前加上关键字inline②再函数定义前加上关键字inline。通常的做法是省略原型,将整个定义放在本应提供原型的地方。
5、程序员请求将函数作为内联函数时,编译器并不一定满足这种要求。而且。内联函数不能递归。
6、引用变量的主要作用是用作函数的形参。
7、可以创建指向rats的引
用和指针(如下),这样,表达式rodents和*prats都可以和rats互换,而表达式&rodents和prats都可以同&rats互换。
int rats=101;
int &rodents=rats;
int *prats=&rats;
8、必须在声明引用或者const指针时进行初始化,指针可以先声明再赋值。
9、不能通过赋值来设置引用!!
int rats=101;
int &rodents=rats;// rodents引用的是rats。
int b=50;
rodents=b;// 这句话仅仅是将b的值赋给rodents!!rodents和rats的值都变成了50,同时, rodents和rats的地址相同,而与b的地址不同。
10、如果想用引用作为函数形参,而又不想改变变量的值,则应使用常量引用(const int &a).
11、如果实参与常量(const)引用参数不匹配,C++将生成临时变量。两种情况:①实参的类型正确,但不是可修改的左值(非左值)②实参的类型不正确,但可以转换为正确的类型。注:非左值包括字面常量和包含多项的表达式。
12、如果声明将引用指定为const,C++将在必要时生成临时变量。这些临时变量只在函数调用期间存在,此后编译器便可以随意将其删除。实际上,对于形参为const引用的C++函数,如果实参不匹配,则其行为类似于按值传递,为确保原始数据不被修改,将使用临时变量来存储值。注:如果接受引用参数的函数的意图是修改作为参数传递的变量,则创建临时变量将阻止这种意图的实现。解决方法是禁止创建临时变量。
13、如果函数调用的参数不是左值或与相应的const引用参数的类型不匹配,则C++将创建类型正确的临时匿名变量,将函数调用的参数的值传给该匿名变量,并让参数来引用该变量。
14、应尽可能将引用形参声明为const。
15、通常将返回的引用声明为const是最好的选择。
16、通常,返回机制将返回值复制到临时存储区域中,随后调用程序将访问该区域的临时拷贝值。然而,返回引用意味着调用程序将直接访问返回值,而不需要拷贝。通常,返回的引用将指向传递给函数的引用,因此调用函数实际上是直接访问自己的一个变量。注:返回引用的函数实际上是被引用的变量的别名。
17、应避免返回一个指向临时变量的引用或者指针!因为函数运行完后,临时变量将不再存在。为避免这种问题,最简单的方法是,返回一个作为参数传递给函数的引用。作为参数的引用将指向调用函数使用的数据,因此返回的引用也将指向这些数据。另一种方法是用new来分配新的存储空间,然后返回指向该内存空间的指针。
18、将const用于引用返回类型,意味着:不能使用返回的引用来直接修改它指向的结构。
19、可以将C-风格字符串,包括引号括起的字符串字面量、以空字符结尾的char数组或者指向char的指针变量,赋给string引用!!因为string类定义了一种char*到string的转换功能。
20、使用引用参数(指针参数)的主要原因有两个:①可以修改调用函数中的数据对象。②通过传递引用而不是整个数据对象,可以提高程序的运行速度。
21、对于形参如何使用的几点指导原则:①如果数据对象是数组,则只能使用指针。②如果数据对象是结构,使用引用或指针。③如果数据对象是类对象,则使用引用。
22、如何设置默认值?必须通过函数原型!!对于带参数列表的函数,必须从右向左添加默认值。也就是说,要为某个参数设置默认值,必须为它右边的所有参数提供默认值。
23、关于函数重载,编译器在检查函数特征标时,将把类型引用和类型本身视为同一个特征标。例如:int a(int x);与int a(int &x);cout<<a(x);参数x与这两个原型都匹配!!
24、将非const值赋给const变量是合法的,反之则是非法的。
25、仅当函数基本执行相同的任务,但使用不同形式的数据时,才应采用函数重载。
26、模板并不创建任何函数,而只是告诉编译器如何定义函数。
27、如果需要多个将同一种算法用于不同类型的函数,请使用模板。注:函数模板不能缩短执行程序!最终的代码不包含任何模板,而只是包含为程序生成的实际 函数。
28、需要多个对不同类型使用同一种算法的函数时,可使用模板。不过,并非所有的类型都使用相同的算法。为满足这种需求,可以像重载常规函数定义那样重载模板定义。和常规函数重载语一样,被重载的模板的函数特征标必须不同。
29、模板函数的具体化函数定义——显示具体化。当编译器找到与函数调用匹配的具体化定义后,将使用该定义,而不再寻找模板。
①对于给定的函数名,可以有非模板函数、模板函数和显式具体化模板函数以及它们的重载版本。
②显式具体化的原型和定义应以template<>打头,并通过名称来指出类型。
③具体化将覆盖常规模板,而非模板函数将覆盖具体化和常规函数。即:编译器在选择原型时,如果有多个原型,非模板版本将优先于显式具体化和模板版本,而显式具体化将优先于使用模板生成的版本。
例子:
①非模板void swap(int &,int &);
②模板 template<class T>
void swap(T &,T &);
③显式具体化 template<> void swap<int>(int &,int &);或者 template<> void swap(int &,int &);
30、实例化:编译器使用模板为特定类型生成函数定义时,得到的是模板实例。比如有一个模板函数 template<class T>void swap(T &,T &);函数调用swap(i,j)导致编译器生成swap()的一个实例,该实例使用int类型。模板并非函数定义,但使用int的模板实例是函数定义。这种实例化方式被称为隐式实例化。显示实例化的格式为:template void swap<int>(int,int);编译器看到这种声明后,将使用swap模板生成一个使用int类型的实例。注:显示具体化和显示实例化不同。试图在同一个编程单元中使用同一个类型的显式实例和显式具体化将出错。
31、隐式实例化、显式实例化和显式具体化统称为具体化。相同之处是:它们表示的都是使用具体类型的函数定义,而不是通用描述。
32、对于函数重载、函数模板和函数模板重载,C++来决定为函数调用使用哪一个函数定义,尤其是有多个参数时。这个过程称为重载解析。
33、重载解析将寻找最匹配的函数。如果只存在一个这样的函数,则选择它。如果存在多个这样的函数,但其中只有一个是非模板函数,则选择该函数;如果存在多个合适的函数,并且它们都为模板函数,但其中有一个函数比其他函数更具体,则选择该函数。如果有多个同样合适的非模板函数或者模板函数,但没有一个函数比其他函数更具体,则函数调用是不确定的,因此是错误的。
《C++ Primer Plus》读书笔记之六—函数探幽的更多相关文章
- C++ primer plus读书笔记——第8章 函数探幽
第8章 函数探幽 1. 对于内联函数,编译器将使用相应的函数代码替换函数调用,程序无需跳到一个位置执行代码,再调回来.因此,内联函数的运行速度比常规函数稍快,但代价是需要占用更多内存. 2. 要使用内 ...
- 《C#图解教程》读书笔记之六:接口和转换
本篇已收录至<C#图解教程>读书笔记目录贴,点击访问该目录可获取更多内容. 一.接口那点事儿 (1)什么是接口? 一组函数成员而未实现的引用类型.只有类和结构能实现接口. (2)从ICom ...
- C语言深度解剖读书笔记(6.函数的核心)
对于本节的函数内容其实就没什么难点了,但是对于函数这节又涉及到了顺序点的问题,我觉得可以还是忽略吧. 本节知识点: 1.函数中的顺序点:f(k,k++); 这样的问题大多跟编译器有关,不要去刻意追求 ...
- 《C++ Primer》读书笔记 第一章
读<C++ Primer>才知道,自己对C++知之甚少... 写个博客记录下自己C++的成长,只是读书笔记,不是对<C++ Primer>知识点的总结,而是对自己在书上看到的以 ...
- C++ Primer Plus读书笔记
第五章 循环和关系表达式 1. 2.类别别名: (1) #define FLOAT_POINTER float * FLOAT_POINTER pa, pb; 预处理器置换将该声明转换成 flo ...
- C++ Primer Plus读书笔记(八)函数探幽
1.内联函数 inline int square(x) {return x*x} 2.引用变量 int& 中的& 不是地址运算符,就想定义指针时的char* 一样,int&指的 ...
- 《C++ Primer Plus》读书笔记之五—函数-C++的编程模块
函数-C++的编程模块 1.C++对于返回值的类型有一定的限制:不能是数组,但可以是其他任何类型——整数.浮点数.指针,甚至可以是结构和对象(有趣的是,虽然C++函数不能直接返回数组,但可以将数组 ...
- C++ Primer Plus读书笔记(七)函数
1.声明 void fun1(); //该声明在C中的意思是不指定参数,但是在C++中是指定参数为void void func2(...); //C++中不指定参数 2.函数参数为数组区间 STL有数 ...
- C++ primer plus读书笔记——第7章 函数——C++的编程模块
第7章 函数--C++的编程模块 1. 函数的返回类型不能是数组,但可以是其他任何一种类型,甚至可以是结构和对象.有趣的是,C++函数不能直接返回数组,但可以将数组作为结构或对象的组成部分来返回. 2 ...
随机推荐
- Oracle数据库之PL/SQL程序基础设计
一.PL/SQL块结构 前边我们已经介绍了PL/SQL块的结构,再来回顾一下: DECLARE /* * 声明部分——定义常量.变量.复杂数据类型.游标.用户自定义异常 */ BEGIN /* * 执 ...
- 记laravel5.5项目php-fpm迁移到swoole4.2.9
事起说明 最近对上线半年多的laravel项目做了一次少大的改动,由php-fpm改为swoole,这里做个记录. 2019年过年前半个月,上阿里云后台查看前一天的访问请求日志,发现很多接口响应慢.翻 ...
- 我理解的js中预解释
浏览器在执行代码前,先找带var和带function的地方,把带var的声明且赋予初始值undefined,把带function的声明且定义. 带var关键字预解释 让我们先看下这段代码执行的结果: ...
- Redis--redis集群环境搭建
1.redis-cluster架构图 Redis 自3.0以后开始支持集群.从上图我们可以看出,redis集群的每个节点之间都进行相互通信,在redis集群中,不存在代理层,即没有固定的入口.redi ...
- springboots 配置文件
1.build.gradle buildscript { // 声明变量 ext { springBootVersion = '1.5.2.RELEASE' } // 仓库 repositories ...
- PHP中关于时间(戳)、时区、本地时间、UTC时间等的梳理
PHP中关于时间(戳).时区.本地时间.UTC时间等的梳理 在PHP开发中,我们经常会在时间问题上被搞糊涂,比如我们希望显示一个北京时间,但是当我们使用date函数进行输出时,却发现少了8个小时.几乎 ...
- Oracle11g密码过期处理方法
首先 查询密码有效期: SELECT * FROM dba_profiles s WHERE s.profile='DEFAULT' AND resource_name='PASSWORD_LIF ...
- Node.js学习笔记(八) --- Node.js的路由模块封装
1 .模块化的方式封装 整理中… 2 .封装仿照 express 的路由整理中…
- CentOS 7 防火墙端口配置
CentOS 7 防火墙端口配置查看防火墙是否开启systemctl status firewalld 若没有开启则开启systemctl start firewalld 查看所有开启的端口firew ...
- string.replace替换
var str = 'abcadeacf'; var str1 = str.replace('a', 'o'); alert(str1); // 打印结果: obcadeacf var str2 = ...