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一样的复制和赋值能力(意味着复制和赋值后,两个对象没有任何关联,或者逻辑上看起来无任何关联),那么就称这个类的对象为值语义;如果类不能复制,或者复制后对象之间的资源归属纠缠不清,那么称为对象语义,或引用语义

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。