C++——基础学习中的一些重点笔记
1.异常处理:
a)在try块中,一旦发生错误,立即抛出异常,然后转入catch块中(try块中剩余的代码不会被执行)。
b)如果throw异常不去捕获,会造成程序core dump(异常处理没有对应的代码块,同样会引起core dump)。
c)对于不同类型的异常,可以采用不同的catch块分别对其进行处理,也可以采取统一处理(越是通用的异常处理handle,越应该放到最后)。
d)异常在某函数中没有相应的处理,就向外继续throw(函数剩余的代码不会执行,程序会立刻退出该程序)。
2.传引用:
a)C语言中的传值,实际上是在函数调用时,将实参的value拷贝给形参(如果传递的类型较复杂,可能造成较大的开销)。
b)在C++中,我们采用传引用来避免对象复制的开销(既可以修改原对象,又可以避免复制的开销)。
c)如果一个函数的形参为A &a,这意味着该函数不仅可以改变a的值,而且期望改变a的值。
d)const引用表示常亮,是一种保护语义,而非const引用,是一种修改语义。
e)绝对不要返回局部对象的引用或指针。
3.宏函数与内联函数:
a)宏函数:
在预处理期间被文本展开。
没有函数调用的开销。
缺点是如果不被调用,编译器就无法为其检查错误(编译器根本就找不到这段代码,因为该段代码预处理期间就消失了)。
b)内联函数:
可以看做高级的宏函数。
在编译期间被内联展开。
没有函数调用的开销。
内联函数需要编译器为其检查语法错误。
4.函数的唯一标示与重载:
a)C++中函数的唯一标示——函数签名,不仅包括函数的名字,还包括参数列表(不包括返回值)。
b)构成函数重载的几点要素:
函数名称(包含类名)。
形参表(形参的类型与个数)。
const属性(类的成员属性)。
5.IO流:
a)C++中IO有三种状态: bad 、fail 、 eof。以cin为例:
如果输入非法数据,cin的 fail 置为1.
如果输入结束,cin的fail与eof都置为1.
b)IO流的修复:
如果是文件结束,那么只需调用clear函数即可。
如果是非法数据,除了clear,还需要清空非法输入(如果不清空,那么数据会一直停留在缓冲区中)。
调用以下函数:
cin.ignore(std::numeric_limits < std::streamsize > ::max(), ‘\n‘);
6.类:
a)一个类分为两大部分,数据与函数(数据可以看做是对象的属性,函数可以看做是对象的行为)。
b)C++类的成员函数,均还有一个隐式的参数,指向调用该函数的对象的指针,即this指针。
c)构造函数也可以重载。
d)初始化式中的语句为变量的初始化,而构造函数块中的语句为变量的赋值。
e)初始化列表中的初始化顺序,与class中变量的定义顺序有关,而与初始化列表中的声明顺序无关。
f)尽可能使用初始化列表代替函数体内的赋值
当class中的成员只能被初始化,而不能被赋值时(例如const成员或引用成员),我们必须使用初始化列表。
当class中的成员的初始化必须由我们手工控制,而不能交给系统默认初始化时(通常原因是该成员没有默认构造函数),我们必须使用初始化列表。
g)class内不写访问标号,默认为private,而struct默认为public。这是二者唯一的区别。
h)C++中的friend声明,是一种单向关系。例如A 声明friend class B表示B是A的friend,可以访问A的private数据,但是反过来则不成立。
7.顺序容器:
a)用一个容器去初始化另一个容器,要求类型完全一致(容器类型相同,元素类型相同)。
b)用迭代器范围去初始化容器,只要求迭代器元素与容器元素类型匹配即可(不要求容器类型相同)。
c)凡是传入迭代器作为指定范围的参数,可以使用指针代替。
d)凡是放入vector中的元素,必须要求具备复制与赋值能力。
e)vector迭代器持续有效,除非:
使用者在较小的索引位置插入或删除元素。
由于容量的变化引起的内存重新分配。
f)用erase删除元素记得接收返回值,同时最好使用while循环。
g)vector的几个与容量有关的函数:
size(), 表示元素数目。
resize(), 调整元素的数目。
capacity(),表示可容纳数目。
reserve(), 调整容量。
h)vector的内存增长是按照成倍增长。
i)vector与list的区别:
vector采用数组实现,list采用链表实现。
vector支持随机访问,list不提供下标
大量增加删除的操作适合使用list。
8.map和set:
a)pair不是容器,而是代表一个key-value键值对。
b)map是存储pair对象的容器,只是存储方式与vector不同,map采用的是二叉排序树存储pair,一般是红黑树。
c)map使用下标访问时,如果key不存在,那么会在map中添加一个新的pair,value为默认值。
d)map的key必须具有小于操作符operator<。
e)使用insert插入map元素时,如果失败,则不会更新原来的值。
f)map与set的比较:
二者均使用红黑树实现。
key需要支持<操作。
map侧重于key-value的快速查找。
set侧重于查看元素是否存在。
g)map和set中的元素都无法排序。
9.reverse迭代器:
a)在逻辑上,rbegin指向最后一个元素,rend指向第一个元素的前一个位置。
b)在实际实现上,rbegin指向最后一个元素的下一个位置,rend指向第一个元素。
c)reverse迭代器的物理位置比逻辑位置增加了1.
d)采用这种实现的好处是:将iterator转化为reverse_iterator之后的区间,与之前的区间恰好相反,但内容相同。
e)reverse迭代器不能用于erase函数。删除的正确方式是:
it = string::reverse_iterator(s.erase((++it).base()));
10.深拷贝与浅拷贝:
a)含有指针成员变量的类在复制时,有两种选择:
复制指针的值,这样复制完毕后,两个对象指向同一块资源,这叫做浅拷贝。
复制指针指向的资源,复制完毕后,两个对象各自拥有自己的资源,这叫做深拷贝。
b)赋值操作符,需要先释放以前持有的资源,同时必须处理自身赋值的问题。
c)复制构造函数、赋值运算符以及析构函数,称为三法则,一旦提供了其中一个,务必提供另外两个。以string为例:
涉及到深拷贝、浅拷贝问题,所以需要提供拷贝构造函数。
为了保持一致,赋值运算符也应该实现深拷贝。
既然实现了深拷贝,那么必定申请了资源(内存),所以需要析构函数手工释放资源。
d)一个空类,编译器默认提供无参构造函数、拷贝构造函数、赋值运算符以及析构函数,一共四个函数。
e)禁止一个类复制与赋值能力的方法:
将copy函数与赋值运算符设为private。
只声明,不实现。
f)复制和赋值必须保证在程序的语义上具有一致性。
g)如果一个类,不需要复制与赋值,那就禁用这种能力,可以避免大量潜在的bug。
h)如果一个类,实现了像value一样的复制和赋值能力(意味着复制和赋值后,两个对象没有任何关联,或者逻辑上看起来无任何关联),那么就称这个类的对象为值语义;如果类不能复制,或者复制后对象之间的资源归属纠缠不清,那么称为对象语义,或引用语义。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。