Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
ShujiaHuang committed Aug 6, 2021
1 parent d5733d0 commit ce5d8be
Showing 1 changed file with 137 additions and 0 deletions.
137 changes: 137 additions & 0 deletions practice/booknotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -2090,6 +2090,143 @@ C++处理结构体的方式与基本类型完全相同,这意味着可以按



# 第八章 函数探幽

本章内容:

- 内联函数;
- 引用变量;
- 如何按引用传递函数参数;
- 默认参数;
- 函数重载;
- 函数模板;
- 函数模板具体化。

## 8.1 C++ 内联函数

内联函数是C++为提高程序运行速度所做的一项改进。常规函数和内联函数之间的主要区别不在于编写方式,而在于C++编译器如何将它 们组合到程序中。 常规函数调用也使程序跳到另一个地址(函数的地址),并在函数结束时返回。

C++内联函数提供了另一种选择。内联函数的编译代码与其他程序 代码“内联”起来了。也就是说,编译器将使用相应的函数代码替换函数 调用。对于内联代码,程序无需跳到另一个位置处执行代码,再跳回来。因此,内联函数的运行速度比常规函数稍快,但代价是需要占用更多内存。

![image-20210805155012304](https://static.fungenomics.com/images/2021/08/image-20210805155012304.png)

要使用这项特性,必须采取下述措施之一:

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

内联函数最好都是一些很简单、行数少的函数。

## 8.2 引用变量

C++新增了一种复合类型——引用变量。引用是已定义的变量的别 名(另一个名称)。

### 8.2.1 创建引用变量

C++给`&`符号赋 予了另一个含义,将其用来声明引用。例如,要将 `rodents`作为`rats`变量的别名,可以这样做:

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

其中,**`&` 不是地址运算符,而是类型标识符的一部分**。就像声明中的 `char*` 指的是指向 `char` 的指针一样,`int &` 指的是指向 `int` 的引用。

`rodents` 加1将影响这两个变量。更准确地说, `rodents++` 操作将一个有两个名称的变量加1。

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

![image-20210805160617225](https://static.fungenomics.com/images/2021/08/image-20210805160617225.png)

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

**引用是别名**

### 8.2.2 将引用用作函数参数

引用经常被用作函数参数,使得函数中的变量名成为调用程序中的 变量的别名。这种传递参数的方法称为按引用传递。按引用传递允许被 调用的函数能够访问调用函数中的变量。C++新增的这项特性是对C语 言的超越,C语言只能按值传递。按值传递导致被调用函数使用调用程 序的值的拷贝(参见图8.2)。

![image-20210805161500948](https://static.fungenomics.com/images/2021/08/image-20210805161500948.png)

交换函数必须能够修改调用程序中的 变量的值。这意味着按值传递变量将不管用,因为函数将交换原始变量 副本的内容,而不是变量本身的内容。但传递引用时,函数将可以使用 原始数据。另一种方法是,传递指针来访问原始数据。

![image-20210805162214166](https://static.fungenomics.com/images/2021/08/image-20210805162214166.png)

![image-20210805162432252](https://static.fungenomics.com/images/2021/08/image-20210805162432252.png)

### 8.2.3 引用的属性和特别之处
`refcube()` 函数修改了 `main()` 中的 `x` 值,而 `cube()` 没有,这提醒我们为何通常按值传递。变量 `a` 位于 `cube()` 中,它被初始化为 `x` 的值,但修改 `a` 并不会影响 `x`。但由于 `refcube()` 使用了引用参数,因此修改 `ra` 实际上就是修改 `x`。如果只是让函数使用传递给它的信息,而不对这些信 息进行修改,同时又想使用引用,则应使用常量引用。

例如,在这个例子中,应在函数原型和函数头中使用`const`

```Cpp
double refcube(const double &ra);
```
如果要编写类似于上述示例的函数(即使用基本数值 类型),应采用按值传递的方式,而不要采用按引用传递的方式。当数 据比较大(如结构和类)时,引用参数将很有用。
![image-20210805163836749](https://static.fungenomics.com/images/2021/08/image-20210805163836749.png)
### 8.2.4 将引用用于结构体
![image-20210805164836645](https://static.fungenomics.com/images/2021/08/image-20210805164836645.png)
2.为何要返回引用
下面更深入地讨论返回引用与传统返回机制的不同之处。传统返回机制与按值传递函数参数类似:计算关键字return后面的表达式,并将结果返回给调用函数。从概念上说,这个值被复制到一个临时位置,而 调用程序将使用这个值。
> 返回引用的函数实际上是被引用的变量的别名。
3.返回引用时需要注意的问题
返回引用时最重要的一点是,应避免返回函数终止时不再存在的内存单元引用。应**避免**编写如下代码:
![image-20210805165912018](https://static.fungenomics.com/images/2021/08/image-20210805165912018.png)
**该函数返回一个指向临时变量(newguy)的引用,函数运行完毕后 它将不再存在。同样,也应避免返回 指向临时变量的指针。**
为避免这种问题,最简单的方法是,返回一个作为参数传递给函数 的引用。作为参数的引用将指向调用函数使用的数据,因此返回的引用 也将指向这些数据。
4.为何将const用于引用返回类型
### 8.2.5 将引用用于类对象
将类对象传递给函数时,C++通常的做法是使用引用。
![image-20210805171059802](https://static.fungenomics.com/images/2021/08/image-20210805171059802.png)
### 8.2.6 对象、继承和引用
### 8.2.7 何时使用引用参数
使用引用参数的主要原因有两个:
- 能够修改调用函数中的数据对象;
- 通过传递引用而不是整个数据对象,可以提高程序的运行速度。
当数据对象较大时(如结构和类对象),第二个原因最重要。这些也是使用指针参数的原因。这是有道理的,因为引用参数实际上是基于 指针的代码的另一个接口。
使用引用的原则:
![image-20210805171441141](https://static.fungenomics.com/images/2021/08/image-20210805171441141.png)
Expand Down

0 comments on commit ce5d8be

Please sign in to comment.