【Essential C++】面向过程的编程风格

 写完第一章的读后总结,自己都不想去看,只是一味的将书中的语句摘抄下来。从第二章开始,尽可能的在总结中添加自己的一些想法和感悟。

2.1 如何编写函数

阅读本小节,需要知道的重点是 函数的返回类型即使是void,也应该加上 “ return; ”,能显示退出,就不隐式退出,培养一种好的编程习惯。看到本小节,联想到 编程过程中进行类型转换时,隐式转换很容易带来潜在的bug。

本小节中,遇到了我之前很少或几乎就没用过的知识:获取int的最大最小值

#include <limits>
int max_int = numeric_limits<int>::max();
int min_db1 = numeric_limits<int>::min();

读到函数声明和定义这里时,一想到刚学习的时候经常把声明和定义搞混:

函数声明是不必提供函数体,但必须指明返回类型、函数名,以及参数列表。此即所谓的函数原型(function prototype).

函数定义则包括函数原型及函数体。

2.2 调用函数

这一节的重点之一是 函数调用过程中的值传递方式传址(by reference) 和传值(by value)。

如下代码中bubble_sort是传值,将vec[ix]这样的对象传入函数,默认情形下其值会被复制一份,成为参数的局部性定义(local definition),这种方式称为传值。

void bubble_sort(std::vector<int> vec) { /* ... */ }

如下代码中bubble_sort是传址。将vec改为一个reference。

void bubble_sort(std::vector<int>& vec) { /* ... */ }

 将参数声明为reference的理由:一是希望得以直接对所传入的对象进行修改,这一点极为重要;二是降低复制大型对象的额外负担。

如果使用指针传递,传入的参数,需要判断其指针是否非空,使用引用传递,则必定会代表某个对象,不需要进行检查。

这一节的重点之二是 作用域及范围:局部对像(local object)文件作用域(file scope)

函数内定义的对象,只存在于函数执行期间,可如果将这些所谓局部对象(local object)的地址返回,会导致运行时错误。局部对象一出函数的作用域,它所在的区域就会被弃置。

如果是以传值的方式返回,便不会出任何问题,因为返回的乃是对象的副本,它在函数之外依然存在。

对象如果在函数以外声明,具有所谓的file scope,对象如果拥有file scope, 从其声明点至文件末尾都是可见的。file scope内的对象也具备所谓的static extent,意即该对象的内存在main()开始执行之前便已经分配好了,可以一直保存在至程序结束。

内置类型的对象,如果定义在file scope之内,必定被初始化为0,但如果它们被定义于local scope之内,除非程序员指定其初值,否则不会被初始化。

这一节的重点之三是 动态内存管理(堆内存)

这种内存必须由程序员自行管理。使用malloc/new开辟空间,就必须由free/delete释放空间。

如果程序员没有使用free/delete,由heap分配而来额对象就永远不会被释放,这称为内存泄漏(memory leak)

2.3 提供默认参数值

C++允许为全部或部分参数设定默认值。

void bubble_sort(vector<int>& vec, ofstream* ofil = nullptr);

默认的解析操作由最右边开始进行。

// 错误:没有为vec提供默认值
// 设置默认参数值,从左边第一个默认参数值开始,往右的所有参数都必须设置默认参数值
void bubble_sort(ofstream* ofil = nullptr, vector<int>& vec);

默认值只能指定一次,可以在函数声明处,也可以在函数定义处。但不能够在两个地方都指定。

2.4 使用局部静态对象

下一次调用fibon_seq函数,elems保留着上之前调用fibon_seq计算的值。

const vector<int>* fibon_seq( int size)
{
    static vector<int> elems;
    ...
}

2.5 声明inline函数

一般而言,适合声明为inline函数的条件是:体积小,常被调用,所从事的计算并不复杂(即函数体不超过十行,没有for循环)

inline bool fibon_elem(int pos, int& elem);

2.6 提供重载函数

重载函数:参数列表不相同(可能是参数类型不同可能是个数不同)的两个或多个函数,可以拥有相同的函数名称。

返回类型不能作为区分两个具有相同函数名称的函数,因为返回类型无法保证提供给我们一个足以区分不同重载函数的语境。

2.7 定义并使用模板函数

程序代码的主体不变,仅仅改变其中用到的数据类型,可以通过function template达到目的。模板函数也可以重载。

template <typename elemType>
void display_messsage(const string& msg, const vector<elemType>& vec);
template <typename elemType>
void display_messsage(const string& msg, const list<elemType>& vec);

2.8 函数指针带来更大的弹性

这一节主要讲了函数指针的用法:

函数指针必须指明其所指函数的返回类型及参数列表。此外函数指针的定义必须将*放在某个位置,表示这份定义所表现的是一个指针。最后还需要赋予一个名称。

const vector<int>* (*seq_ptr)(int);

seq_ptr可以指向“具有所列返回类型及参数列表”的任何一个函数。

我们可以基给予函数指针初值,如果初值为nullptr,表示未指向任何函数:

const vector<int>* (*seq_ptr)(int) = nullptr;

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值