第十八章 用于大型程序的工具

大规模应用程序的特殊要求包括:

  • 在独立开发的子系统之间协同处理错误的能力。
  • 使用各种库进行协同开发的能力。
  • 对比较复杂的应用概念建模的能力。

一、异常处理

异常处理(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及其引用限定符之后,finaloverride或虚函数的=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 》第十八章的更多相关文章

  1. C++Primer 第十八章

    //1.异常:待研究 //2.命名空间: // A:多个库将名字放置在全局命名空间中将引发命名空间污染. // B:命名空间为防止名字冲突提供了更加可控的机制.命名空间分割了全局命名空间,其中每个命名 ...

  2. 《Linux内核设计与实现》读书笔记 第十八章 调试

    第十八章调试 18.1 准备开始          需要准备的东西: l  一个bug:大部分bug通常都不是行为可靠而且定义明确的 l  一个藏匿bug的内核版本:找出bug首先出现的版本 l  相 ...

  3. Python之路【第十八章】:Django基础

    Django基本配置 Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM.模型绑定.模板引擎.缓存.Se ...

  4. 《Linux内核设计与实现》课本第十八章自学笔记——20135203齐岳

    <Linux内核设计与实现>课本第十八章自学笔记 By20135203齐岳 通过打印来调试 printk()是内核提供的格式化打印函数,除了和C库提供的printf()函数功能相同外还有一 ...

  5. 《Linux命令行与shell脚本编程大全》 第十八章 学习笔记

    第十八章:初识sed和gawk 文本处理 sed编辑器 sed编辑器可以基于输入到命令行的或是存储在命令文本文件中的命令来处理数据流中的数据. 它每次读取一行,用提供的编辑器命令匹配数据.按命令中指定 ...

  6. 第十八章 DjangoWeb开发框架

    第十八章 DjangoWeb开发框架 第一课 内容概要: 1.JS正则 -登录注册验证 2.组件 1.BootStrap -css -js 学习BootStrap规则 2.jQueryUI -css ...

  7. Gradle 1.12用户指南翻译——第四十八章. Wrapper 插件

    本文由CSDN博客貌似掉线翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...

  8. Gradle 1.12 翻译——第十八章. 日志

    有关其他已翻译的章节请关注Github上的项目:https://github.com/msdx/gradledoc/tree/1.12,或访问:http://gradledoc.qiniudn.com ...

  9. Gradle 1.12用户指南翻译——第二十八章. Jetty 插件

    其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Github上的地址: https://g ...

随机推荐

  1. 认识 Cargo-Rust构建工具和包管理器

    认识 Cargo-Rust构建工具和包管理器 上两篇文章 都有说到 hello world 程序,但是我们如果使用自己创建文件的方式创建项目,一旦文件多了,那得多麻烦,整个项目将变得难以管理.下面我来 ...

  2. AcWing 276. I-区域

    题目链接 设 \(0\) 为单调伸长, \(1\) 为单调伸短. 设 \(f[i][j][l][r][x(0 / 1)][y (0 / 1)]\) 为第 \(i\) 行,已经选出\(j\)个格子,第\ ...

  3. 题解-Infinite Path

    题解-Infinite Path \(\color{#9933cc}{\texttt{Infinite Path}}\) \(T\) 组测试数据.每次给你一个 \(n\) 的排列 \(\{p_n\}\ ...

  4. 一文入门Redis

    一文入门Redis 目录 一文入门Redis 一.Redis简介 二.常用数据类型 1.String(字符串) 2.Hash(哈希) 3.List(列表) 4.Set(集合) 5.Zset(有序集合) ...

  5. learn Docker from scratch (1)

    一.前言 Docker容器一个很有趣的东西,下面链接内容适合docker的入门非常棒! 链接如下: http://www.ruanyifeng.com/blog/2018/02/docker-tuto ...

  6. 在Linux下下载RPM包

    在Linux下下载RPM包,但是不安装 在工作中经常会遇到离线安装RPM包的情况,下面是下载RPM包的方法 # 使用yum下载RPM包 yum -y install --downloadonly &l ...

  7. HBase按照TimeStamp删除数据

    #!/bin/bash #两种时间输入,一种是输入起始日期,另一种是直接输入hbase里面数据的起始时间戳 if [ $# != 5 ];then echo 'usage:sh byTimestamp ...

  8. YT Downloader视频下载器

    简介 YT Downloader视频下载器是一款非常知名的视频下载器,支持下载YouTube,Facebook,Dailymotion,Vimeo,Metacafe等数百个视频网站的视频 截图介绍 小 ...

  9. Python循环语句代码详解:while、for、break

    1 while循环 循环语句是程序设计中常用的语句之一.任何编程语言都有while循环,Python也不例外.while循环的格式如下所示.  while(表达式):       -   else:  ...

  10. 2020年的UWP(5)——UWP和Desktop Extension的双向交互

    上一篇我们提到了怎么在Desktop Extension中等待并处理UWP端发出的request.在本篇中将描述UWP和Desktop Extension双向交互的场景,即存在从两端各自发出reque ...