【C++】《C++ Primer 》第十八章
第十八章 用于大型程序的工具
大规模应用程序的特殊要求包括:
- 在独立开发的子系统之间协同处理错误的能力。
- 使用各种库进行协同开发的能力。
- 对比较复杂的应用概念建模的能力。
一、异常处理
异常处理(exception handling) 机制允许程序中独立开发的部分能够在运行时就出现的问题进行通信并作出相应的处理。
1. 抛出异常
- 一个异常如果没有被捕获,则它将终止当前的程序。
- 在栈展开的过程中,运行类类型的局部对象的析构函数。因为这些析构函数是自动执行的,所以它们不应该抛出异常。一旦在栈展开的过程中析构函数抛出了异常,并且析构函数自身没能捕获到该异常,则程序将被终止。
- 当抛出一条表达式时,该表达式的静态编译时类型决定了异常对象的类型。抛出指针要求在任何对应的处理代码存在的地方,指针所指的对象都必须存在。
2. 捕获异常
- 通常情况下,如果
catch接受的异常与某个继承体系有关,则最好将该catch的阐述定义为引用类型。 - 如果在多个
catch语句的类型之间存在着继承关系,则我们应该把继承链最低端的类放在前面,而将继承链最顶端的类放在后面。 - 如果
catch(...)与其他几个catch语句一起出现,则catch(...)必须在最后的位置。出现在捕获所有异常语句后面的catch语句将永远不会被匹配。
3. 函数try语句块与构造函数
- 处理构造函数初始值异常的唯一方法是将构造函数写成函数try语句块。
4. noexcept异常说明
- C++11新标准中,通过提供
noexcept说明符指定某个函数不会抛出异常。
void recoup(int) noexcept; // 不会抛出异常
void alloc(int); // 可能抛出异常
- 可以在函数指针的声明和定义中指定
noexcept;在typedef或类型别名中则不能出现noexcept;在成员函数中,noexcept说明符需要跟在const及其引用限定符之后,final、override或虚函数的=0之前。 noexcept可以用在两种情况下:确定函数不会抛出异常;根本不知道该如何处理异常;- 通常情况下,编译器不能也不必在编译时验证异常说明。
noexcept有两层含义:当跟在函数参数列表后面时它是异常说明符;而当作为noexcept异常说明的bool实参出现时,它是一个运算符。
5. 异常类层次
- 标准exception层次:

- 书店应用程序的异常类
class out_of_staock: public std::runtime_error {
public:
explicit out_of_stock(const std::string &s): std::runtime_error(s) {}
};
class isbn_mismatch: public std::logic_error {
public:
explicit isbn_mismatch(const std::string &s): std::logic_error(s) {}
isbn_mismatch(const std::string &s, const std::string &lhs, const std::string &rhs): std::logic_error(s), left(lhs), right(rhs) {}
const std::string left. right;
};
// 使用自定义异常类
Sales_data &Sales_data::operator += (const Sales_data& rhs) {
if(isbn() != rhs.isbn())
throw isbn_mismatch("wrong isbn", isbn(), rhs.isbn());
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
Sales_data item1, item2, sum;
while (cin >> item1 >> item2) {
try {
sum = item1 + item2;
} catch (const isbn_mismatch &e) {
cerr << e.what() << ": left isbn(" << e.left << ") right isbn (" << e.right << ")" << endl;
}
}
二、命名空间
多个库将名字放置在全局命名空间中将引发命名空间污染。命名空间(namespace) 为防止名字冲突提供了更加可控的机制。
1. 命名空间定义
- 一个命名空间的定义包括两个部分:首先是关键字namespace,随后是命名空间的名字。在命名空间名字后面是一系列由花括号括起来的声明和定义。只要能出现在全局作用域中的声明就能置于命名空间内,主要包括:类、变量(及其初始化操作)、函数(及其定义)、模板和其他命名空间。
namespace cplusplus_primer {
class Sales_data {};
Sales_data operator+(const Sales_data&, const Sales_data&);
class Query {};
class Query_base {};
}
// 使用
cplusplus_primer::Query q = cplusplus_primer::Query("hello");
- 定义多个类型不相关的命名空间应该使用单独的文件分别表示每个类型(或关联类型构造的集合)。
- 未命名的命名空间是指关键字namespace后紧跟花括号括起来的一系列声明语句。它定义的变量拥有静态生命周期;他们在第一次使用前创建,并且直到程序结束时才销毁。和其他命名空间不同,未命名的命名空间仅在特定的文件内部有效,其作用范围不会横跨多个不同的文件。
int i; // i的全局声明
namespace local {
namespace {
int i;
}
}
local::i = 42;
- 未命名的命名空间取代文件的静态声明。
2. 使用命名空间成员
- 一个命名空间可以有好几个同义词或别名,所有别名都与命名空间原来的名字等价。
namespace cplusplus_primer {};
namespace primer = cplusplus_primer;
- 避免
using指示
3. 类、命名空间与作用域
- 对命名空间内部名字的查找遵循常规的查找规则:即由内向外依次查找每个外层作用域。外层作用域也可能是一个或多个嵌套的命名空间,直到最外层的全局命名空间查找过程终止。只有位于开放的块中且在使用点之前的名字才被考虑。
- 可以从函数的限定名与推断出查找名字时检查作用域的次序,限定名以相反次序指出被查找的作用域。
4. 重载与命名空间
using声明语句声明的是一个名字,而非特定的函数,也就是包括该函数的所有版本,都被引入到当前作用域中。
三、多重继承与虚继承
1. 多重继承
2. 类型转换与多个基类
3. 多重继承下的类作用域
- 当一个类拥有多个基类时,有可能出现派生类从两个或更多基类中继承了同名成员的情况。此时,不加前缀限定符直接使用该名字将引发二义性。
4. 虚继承
- 虚继承的目的是令某个类做出声明,承诺愿意共享它的基类。其中,共享的基类子对象成为虚基类。在这种机制下,不论虚基类在继承体系中出现了多少次,在派生类中都只包含唯一一个共享的虚基类子对象。
- 虚派生只影响从指定了虚基类的派生类中进一步派生出的类,它不会影响派生类本身。
5. 构造函数与虚继承
- h含有虚基类的对象的构造顺序与一般的顺序稍有区别:首先使用提供给最底层派生类构造函数的初始值初始化该对象的虚基类子部分,接下来按照直接基类在派生列表中出现的次序对其进行初始化。
- 虚基类总是先于非虚基类构造,与它们在继承体系中的次序和位置无关。
【C++】《C++ Primer 》第十八章的更多相关文章
- C++Primer 第十八章
//1.异常:待研究 //2.命名空间: // A:多个库将名字放置在全局命名空间中将引发命名空间污染. // B:命名空间为防止名字冲突提供了更加可控的机制.命名空间分割了全局命名空间,其中每个命名 ...
- 《Linux内核设计与实现》读书笔记 第十八章 调试
第十八章调试 18.1 准备开始 需要准备的东西: l 一个bug:大部分bug通常都不是行为可靠而且定义明确的 l 一个藏匿bug的内核版本:找出bug首先出现的版本 l 相 ...
- Python之路【第十八章】:Django基础
Django基本配置 Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM.模型绑定.模板引擎.缓存.Se ...
- 《Linux内核设计与实现》课本第十八章自学笔记——20135203齐岳
<Linux内核设计与实现>课本第十八章自学笔记 By20135203齐岳 通过打印来调试 printk()是内核提供的格式化打印函数,除了和C库提供的printf()函数功能相同外还有一 ...
- 《Linux命令行与shell脚本编程大全》 第十八章 学习笔记
第十八章:初识sed和gawk 文本处理 sed编辑器 sed编辑器可以基于输入到命令行的或是存储在命令文本文件中的命令来处理数据流中的数据. 它每次读取一行,用提供的编辑器命令匹配数据.按命令中指定 ...
- 第十八章 DjangoWeb开发框架
第十八章 DjangoWeb开发框架 第一课 内容概要: 1.JS正则 -登录注册验证 2.组件 1.BootStrap -css -js 学习BootStrap规则 2.jQueryUI -css ...
- Gradle 1.12用户指南翻译——第四十八章. Wrapper 插件
本文由CSDN博客貌似掉线翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...
- Gradle 1.12 翻译——第十八章. 日志
有关其他已翻译的章节请关注Github上的项目:https://github.com/msdx/gradledoc/tree/1.12,或访问:http://gradledoc.qiniudn.com ...
- Gradle 1.12用户指南翻译——第二十八章. Jetty 插件
其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Github上的地址: https://g ...
随机推荐
- 获取浏览器URL中查询字符串中的参数
//http://www.runoob.com/index.html?name=xiaoming&age=23function showWindowHref(){ var sHref = wi ...
- CCF统一省选 Day2 题解
此题解是教练给我的作业,AK了本场比赛的人,以及认为题目简单的人可以不必看 T1 算法一 暴力枚举对信号站顺序的不同排列,然后对代价取\(\min\)即可. 时间复杂度\(O(m! \cdot n)\ ...
- git使用-merge request开发操作步骤
0. 如果当前不在develop分支,则切换到develop分支 git checkout develop 1. 获取develop分支最新代码 git pull 注意:这一步正常来说应该是一个Fas ...
- windows 远程连接报错
在windows7上或者windows10上远程连接服务器报错("连接错误"),试了网上的方法,发现是服务器安装ssl证书关闭了ssh服务,开启ssh服务后,重启电脑就可以解决这个 ...
- 关于C++的异常抛出
在接触 throw 之前,我们只知道可以通过函数的返回值来获取和定位错误,比如通过 return 来层层返回是一种方法,但如果牵扯到多层函数调用,那么通过 return 来返回错误显得过于拖沓,这时就 ...
- S3C2440从NAND Flash启动和NOR FLASH启动的问题
1.为什么NAND FLASH不能直接运行程序 NAND FLASH本身是连接到了控制器上而不是系统总线上.CPU运行机制为:CPU启动后是要取指令执行的,如果是SROM.NOR FLASH ...
- 【opencv】学习笔记
安装 此笔记仅对python36实用 OpenCV装3.4.1.15 指令:pip install -i https://pypi.tuna.tsinghua.edu.cn/simple opencv ...
- MySQL最经典50道练习题
表名和字段 学生表 Student(s_id,s_name,s_birth,s_sex):学生编号.学生姓名.出生年月.学生性别. 课程表 Course(c_id,c_name,t_id):课程编号. ...
- Nginx(三):反向代理,负载均衡
环境准备 配置反向代理,负载均衡,动静分离需要的必备环境,JDK,2个tomcat开启8080和8081端口. 安装jdk [root@localhost ~]# rpm -qa|grep jav ...
- IDEA中flink程序报错找不到类
Idea中运行flink程序,报错找不到类,其中pom文件中一项依赖为: <dependency> <groupId>org.apache.flink</groupId& ...