Essential C++读书笔记1/2

时间:2022-12-09 04:17:11

第一章 C++编程基础

1.初始化两种方式:int a=10;int a(10);第一种使用等于是继承自C语言的风格。第二种出现的原因是因为的变量可能初始化值有多个,例如complex。

2.定义vector指针:vector<int>*pv=&vec1;定义vector指针数组:vector<int>*pv[2]={&vec1,&vec2};

3.产生随机数可以使用C语言中的srand()和rand()。其中,前者接收一个int参数作为种子,然后srand函数的结果对rand进行初始化,产生不同的随机数。srand常用的参数有时间函数time(0)等。

4.文件操作。头文件fstream。写文件:ostream ofile("filename.txt");读取文件:istreamifile("filename.txt");读写文件有很多不同的模式,例如同时读写等。

第二章 面向过程的编程风格

1.费波纳切数列非递归实现(第pos个元素):

int elem=1;

int n1=1,n2=1;

//第一第二位置返回1

for(int i=3;i<=pos;i++)

{

   elem=n1+n2;

    n2=n1;n1=elem;

}

2.引用作为函数参数时,对象本身不会复制,复制的是对象的地址。这样能够对对象直接操作并节省复制对象的开销。而且,引用由于必须初始化,因此不用做指针的是否为空检查。

3.内置数据类型全局自动初始化为0,非全局需要用户初始化。

4.默认参数值:void display(int a,int b=0){};默认规则:

a.解析操作从右自左。因此,定义默认值参数右边的参数必须全部定义参数值。

b.函数声明的头文件中需要写明默认值,实现文件中不需要写明默认值。

5.关于函数的返回值:如果返回的是函数中局部变量的指针、引用,该函数都无法正常返回自己想要的结果;如果返回的是函数中局部变量的值,返回时局部变量会进行对象复制,虽然浪费空间,但是函数调用结束后,返回的对象仍然存在。例如三个函数:vector<int>* get()、vector<int>& get()、和vec<int> get(),三个get函数中返回自定义的局部vector。

6.局部静态变量在函数的调用中,其值始终存在。

7.inline定义的函数,表示编译器在每个函数的调用点上将函数展开。inline能够将不同的子函数连接起来形成以个统一的函数。

8.函数的重载根据的是参数列表的不同(参数类型,参数个数、顺序等),函数返回值的不同不能构成函数的重载。

9.可以功能相似的函数定义为模板函数,由用户定义数据类型,函数实现特定数据类型的功能。模板函数格式如下:

template<typename/class elemType>

void function(vector<elemType> vec)

{

elemType elem =vec[0];

}

10.如果函数具备多种实现方式,使用重载,每份提供的是相同的服务;如果希望程序代码主体不变,仅仅改变的是数据类型,可以使用函模板函数。此外,模板函数也可以重载。

11.函数指针:

typedef void(*pf)();

void sayHello()

{

       cout<<"Hello!"<<endl;

}

int main()

{

       pfpf1;

       pf1= sayHello;

       (*pf1)();

       return0;

}

第三章 泛型编程风格

1.STL(标准模板库)包括container(容器)和generic algorithm(泛型算法)。

2.容器包括顺序容器(如vector、list等)和关联容器(如map、set等)。

3.map是key/value组合,set只有key。map和set的key不能重复。

4.泛型算法通过模板函数实现。

5.C++中指针如果作为函数参数或者函数返回值,只有数组的第一个值会被传递。

6.vector的本质是内存连续的数组,list的本质是双向链表。因为vector和list的实现方式不同,因此泛型函数find不能通过指针进行参数传递(vector合适,但是list不合适)。因此需要加入抽象层,提供vector和list的起始元素指针。这就是iterator的由来。

7.所有容器的共通操作:

= =、! =返回true或者false;

=容器复制;

Empty()返回true或者false;

Size()返回容器元素个数;

Clear()删除所有元素;

Begin()返回iterator,指向第一个元素;

End()返回iterator,返回最后一个元素;

Insert()插入元素;

Erase()删除一定范围内的元素。

8.顺序容器:

Vector:数组实现,连续内存区域,读取效率高,删除、插入(非尾部)效率低。

List:双链表实现,非连续内存区域,插入删除效率高,读取效率低。

Deque:连续内存区域,对于最前段的插入、删除效率高,尾部效率也高(同vector)。

9.使用顺序容器(vector、list、deque)

添加、删除尾部元素:push_back()、pop_back()

添加、删除首部元素(除vector):push_front()、pop_front()

获取首尾元素:front()、back()

插入元素:insert()

删除元素:erase()

10.使用泛型算法:需要包含algorithm头文件

泛型搜索算法:

find():无序集合搜索,搜索范围[first,last])。存在返回该元素的iterator,不存在返回指向last的iterator。对象的比较,find可以通过重载等号运算符==进行;find_if用于用户自定义比较规则。

binary_search():有序集合搜索。存在返回true,不存在返回false。效率较find()高。

count():返回数值相符合元素的数目。

search():查找是否存在子序列,如查找[1,3,5]中是否含有[3,5]等。存在返回子序列的iterator,不存在返回指向容器尾部的iterator。

获取最大值:

max_element():传入一对iterator,返回该范围内的最大值。

复制:

copy():接受三个iterator,前两个标示处带赋值元素的范围,第三个标示处复制目的地的iterator,要确保目的iterator有足够的空间存储元素。

11.设计泛型算法:例如,找出vector中小于10的数字。为了扩展函数的通用性,设计函数如下:vector<int>filter(const vector<int> &vec, int value, bool (*pred)(int,int));其中,函数指针用于指定不同元素之间的关系比较,例如大于、小于等,采用函数指针实现。

12.函数对象(Fuction Object):某种class的实例对象,该class对函数调用运算符做了重载操作,使函数对象可以当成一般函数来使用。

算数运算符(6个):

plus<type>/minus<type>/negate<type>/multiplies<type>/divides<type>/modules<type>

关系运算符(6个):

less<type>/less_equal<type>/greater<type>/greater_equal<type>/equal_to<type>/not_equal_to<type>

逻辑运算符(3个):

logical_and<type>/logical_or<type>/logical_not<type>分别对应&&、||和!。

使用方法:需要包含functional头文件。例如sort中使用:sort(vec.begin(),bec.end(),greater<int>());greater<int>()会产生一个未命名的模板类对象,传递给sort算法。

13.函数对象适配器(Fuction object adapter)可以对函数对象进行修改操作。Binder adapter(绑定适配器)可以将函数对象的参数绑定到特定值,使二元函数对象变为一元函数对象。绑定适配器包括:bind1st:将指定值绑定到第一个操作数;bind2nd:将指定值绑定到第二个操作数。例如:bind2nd(less<int> &lt, int val)将val绑定在less<int>的第二个参数上,使less将每个元素同val对比。

14.使用map:map<string,int>words;words[“conan”] = 1;如果调用的words[“lan”]中lan不在words的key中,map会自动添加lan为key并且赋默认value值为0。Map的遍历:

map<string,int>::iterator it =words.begin();

for(;it!=words.end();++it)

{

       Cout<<”key:”<<it->first<<”value”<<it->second<<endl;

}

Map中元素的查询可以利用map提供的find函数(注意不是泛型函数find):words.find(“conan”);

15.使用set:同map中的key类似,可以使用set提供的count函数超找set中是否含有某值。

16.使用iterator inserter(需要头文件iterator):为了防止容器实现时需要传入的是固定大小(这样需要考虑赋值时目标空间是否足够等因素),因此insertion adapter出现,用于避免容器的赋值运算符。Insertion adapter包括:

back_inserter():用容器的push_back()取代赋值运算符。

例如:unique_copy(ivec.begin(),ivec.end(),back_inserter(res_vec));

inserter():insert()代替赋值运算符。

front_inserter():push_front()代替赋值赋值运算。

17.使用iostream iterator:iostream iterator支持单一类型的元素的读取和写入。