Essential C++ note
记录本书(对我来说)的一些重点内容
1 C++编程基础
- 初始化方法:构造函数法(constructor syntax)
1 | int var(66); |
- srand()随机数种子;rand()则产生一个介于0和int所能表示的最大整数;需包含头文件cstdlib
- cerr(standard error)代表标准错误设备,与cout唯一区别就是不带缓冲,立即显示于用户终端
2 面向过程的编程风格
- 使用模板,则声明与定义要放在一起
- 函数指针
1 | // 给函数指针赋初值 |
- inline函数的声明和定义都需要放在头文件,声明和定义有一个标明inline即可(在类定义中实现则默认是inline);其他的函数,则必须是**“定义放在程序代码文件”、“声明放在头文件”**
- 多文件共享变量
1 | /* |
3 泛型编程风格
- list不支持iterator的偏移运算(+、-)但是有++和–
- 对于标准容器,不确保目标空间大小,可使用iterator inserter用插入操作替代赋值操作
- <这章挺多东西,需要结合书本去看>
4 基于对象的编程风格
- 如果有必要为某个class编写[拷贝构造],则同样有必要为它编写[赋值操作]
- 没有一个const reference class参数可以调用公开接口中的non-const成分
- 类中的变量声明为mutable,标明其不会破坏对象的常量性(constness),即可在const函数中可以修改它
- 当定义class的static function时,不可加上关键字static(同理静态成员变量)
- 当类中有静态成员变量时,需要及时在类外进行初始化,否则报错:无法解析的外部命令
- 通常情况:operator*无参表示解引用;有参表示乘法
- friend声明可以出现在类定义任意位置,不受public或private影响
- 嵌套类型(Nested Type),类中可以定义嵌套类型,再用域解析符(例如每个STL容器类都有自己的iterator)
- 重载iostream(看书)
- 类的函数指针:
1 | void (num_sequence::*pm)(int) = 0; |
5 面向对象编程风格
- 纯虚函数:将虚函数赋值为0
1 | virtual void gen_elems(int pos) = 0; |
- 任何类声明了纯虚函数,那么由于其接口不完整(无定义),程序无法为其产生实体。这种类只能作为派生类的子对象使用,而且前提是这些派生类为所有虚函数提供确切的定义。
- 一般规则:凡基类定义了虚函数,则destructor也要声明为virtual
- 一般而言,对象的拷贝构造函数开发者如果未提供,则编译器会自动生成默认的拷贝构造函数。然而以下情况默认的拷贝构造函数会被删除:
1 | /* |
- 在基类的constructor中,派生类的虚函数不允许被调用
- static_cast和dynamic_cast,前者无条件转换,后者判断(比如基类的指针是否真的指向了该派生类)是否可以转换为目的类型再进行转换
6 以template进行编程
- 函数传入一个指针,只能改变指针所指对象的内容,要想改变指针本身(指向)就要传递reference to pointer
1 | BTnode*& prev // 可以看成BTnode* &prev 或 ((BTnode*)&) prev |
- 模板类声明友元的问题:
1 | // 下面代码直接运行会报错:无法解析的外部命令 |
1 | template <typename T> |
1 | /* |
- 非类型参数
1 | /* |
7 异常处理
- 重新抛出时,只需写下关键字throw即可。它只能出现于catch子句中
- 局部资源管理,在易发生异常后释放资源是一件风险很大的事情。虽然可以通过try catch处理,但是释放资源的代码要出现两次,不好。这就引出了resource acquisition is initialization(RAII)策略,即初始化阶段进行资源请求。说人话就是,在构造函数中请求所有资源,在析构函数中释放所有资源:C++保证,在异常处理机制终结某个函数之前,所有局部对象的destructor都会被调用。或者使用智能指针例如:unique_ptr、shared_ptr等。
- ptext = new vector
; 经过以下几个步骤(异常出现,余下不会执行,会沿着调用链抛出)
1 | /* |