东阳的学习记录
第17章(标准库特殊设施)
没啥需要注意的,这章知识一些工具
- tuple
- bitset
- 正则表达式
- 随机数
- IO库再探
第18章
异常处理
- 析构函数不应该抛出不能被它自身处理的异常
- throw语句抛出的局部变量在catch之前就已经被释放
- throw语句中,静态类型决定异常类型,注意throw抛出基类指针时(自定义异常类)
- 异常和catch的匹配规则受到很多限制:(只有以下三种被允许)
i. 允许从非常量到常量的类型转换
ii. 允许派生类向基类的类型转换
iii. 允许指针转换(数组/函数) - 重新抛出异常
- 捕获所有异常 catch(…)
- noexcept异常声明,以执行某些特殊的优化
- ?什么时候应该使用noexcept呢
- what函数不应该抛出异常(不然会造成无限循环)
- using声明的作用域:从声明的地方开始,一直到using声明所在的作用域结束为止
- using指示一般被看作是出现在最近的外层作用域中
- 头文件中使用using,应在局部作用域内
- using只能声明名字,不能声明特定版本
多继承与虚继承
- 查找过程沿着继承体系自底向上进行,直到找到所需的名字,派生类的名字将隐藏基类的同名成员
- 虚继承,防止多次继承(含有多个拷贝)
- 比如在io库中,需要iostream 共享同一个base基类,如果不用虚继承,将会存在多份拷贝,不能满足要求
- 虚函数由最底层的派生类初始化
第19章(特殊工具与技术)
- new/delete隐式静态(必须静态,因为在构造函数之前,对象销毁之后使用)
- new/delete返回值必须是void*
- 不允许定义的版本:void operator new(size_t, void)
- 定位new表达式
- 什么情况下你应该使用dynamic_cast 替代虚函数?
answer: 当我们想要使用基类对象的指针或引用去执行某个派生类操作并且该操作不是虚函数时
运行时类型识别
- typeid() 判断表达式的运行时类型
- 当typeid作用于指针时,返回的是指针的静态类型(编译时类型)
- 继承体系中equal的实现(使用动态转换)
枚举类型
- 枚举成员是const
- 指定enum大小
- 限定作用域和不限定作用域:
i. 不限定: enum intVal: unsigned long long; // 不限定作用域的必须指定成员类型
ii. 限定: enum class open_modes; // 限定作用域可以使用默认的int - 枚举成员永远都不会提升成unsigned
- 成员函数指针
- 将成员函数用作可调用对象
void t19_18()
{
std::vector<std::string> svec {"", "hello", "sad"};
std::function<bool (const std::string *)> fp = &std::string::empty; // function<>
auto fp2 = std::mem_fn(&std::string::empty); // mem_fn,即可对象调用,又可指针调用
auto count = std::count_if(svec.begin(), svec.end(),
std::bind(&std::string::empty, std::placeholders::_1)); // bind
std::cout << "counts of empty vec: " << count << std::endl;
}
嵌套类
- 嵌套类:作为另一个类的成员的类,外层类可以像使用成员一样使用嵌套类
- 嵌套类与外层类是相互独立的:嵌套类只包含嵌套类的成员,外层类只包含外层类的成员
共用体union
- union定义了一个新类型
- union不能含有引用对象
- union不能函数虚函数
- union中含有类类型成员时(一定注意):
i. 改为类类型的值时,需运行构造函数
ii. 改为其他值时需运行析构函数
固有的不可移植特性
- 位域
- volatile限定符:volatile告诉编译器不要对该对象进行优化
- 合成的拷贝对volatile无效(是否需要拷贝?)只要将形参指定为const volatile引用就可以自定义拷贝和移动操作。
- 链接指示 extern “C”:声明一个非C++函数(例如C)