第17章 用于大型程序的工具
大规模应用程序往往具有下列特殊要求:更严格的正常运转时间以及更健壮的错误检测和错误处理;能够用各种库构造程序;能够处理更复杂的应用概念
17.1 异常处理
使用异常处理,程序中独立开发的各部分 能够就 程序执行期间出现的问题相互通信,并处理这些问题,提供异常我们能够将问题的检测和问题的解决分离,这样程序的问题检测部分可以不必了解如何处理问题,异常处理中,由问题检测部分抛出一个对象给处理代码,通过这个对象的类型和内容,两个部分能够就出现了什么错误进行通信
17.1.1 抛出类类型的异常
异常对象 通过复制被抛出表达式的结果创建,该结果必须是可以复制的类型
#include <exception> #include <iostream> double divide(int a, int b){ if(0 == b) throw "Divider cannot be zero\n";//const char* e return 1.0 * a / b; } int main() { try{ double ret = divide(1,0); }catch(const char* e){ std::cerr << e; } return 0; }
17.1.2 栈展开
17.1.3 捕获异常
17.1.4 重新抛出
17.1.5 捕获所有异常的处理代码
17.1.6 函数测试块与构造函数
17.1.7 异常类层次
17.1.8 自动资源释放
17.1.9 auto_ptr类
17.1.10 异常说明
17.1.11 函数指针的异常说明
17.2 命名空间
库定义许多全局名字,主要是模板名、类型名或函数名
命名空间(namespace)为防止名字冲突提供了更加可控的机制,命名空间能够划分全局命名空间,这样使用独立开发的库更加容易,一个命名空间是一个作用域,通过在命名空间内部定义库中的名字,库的作者,可以避免全局名字固有的限制
命名空间定义,以关键字namespace开始,后接命名空间的名字,接着由花括号括住的一块声明和定义,可以在命名空间中放入,可以出现在全局作用域的任意声明:类、变量以及它们的初始化、函数以及它们的定义、模板以及其他命名空间,命名空间作用域不能以分号结束
17.3 多重继承与虚继承
多重继承是从多于一个直接基类派生类的能力,多重继承的派生类继承其所有父类的属性
17.3.1 多重继承
每个抽象级别包含支持广泛用户的数据和操作,在多重继承下,派生类的对象包含每个基类的基类子对象,构造派生类型的对象,包含构造和初始化它的所有基类子对象,构造函数初始化只能控制用于初始化基类的值,不能控制基类的构造次序,基类构造函数按照基类构造函数在 类派生列表 中的出现次序调用,构造函数调用次序既 不受构造函数初始化列表中出现 的基类的影响,也 不受基类在构造函数初始化列表中出现 次序的影响,析构的次序总是按构造函数运行的逆序调用析构函数
17.3.2 转换与多个基类
派生类的指针或引用可以转换为其任意基类的指针或引用,在多重继承情况下,遇到二义性转换的可能性更大,当一个类继承于多个基类的时候,那些基类之间没有隐含的关系,不允许使用一个基类的指针访问其他基类的成员,假定所有根基类都将它们的析构函数适当定义为虚函数,那么,无论通过哪种指针类型删除对象,虚析构函数的处理都是一致的
17.3.3 多重继承派生类的复制控制
多重继承派生类的逐个成员初始化、赋值和析构,使用基类自己的复制构造、赋值操作符或析构函数隐式构造、赋值或撤销每个基类,如果具有多个基类的类定义了自己的析构函数,该析构函数只负责清除派生类,如果派生类定义了自己的复制构造或赋值操作符,则类负责复制(赋值)所有的基类子部分,只有派生类使用复制构造函数或赋值操作符的合成版本,才自动复制或赋值基类部分
17.3.4 多重继承下的类作用域
当一个类有多个基类的时候,通过所有直接基类同时进行名字查找,多重继承的派生类有可能从两个或多个基类继承同名成员,对该成员不加限定的使用是二义性的,可以通过指定使用哪个类解决二义性
17.3.5 虚继承
虚继承是一种机制,类通过虚继承指出它希望共享其虚基类的状态,在虚继承下,对给定虚基类,无论该类在派生层次中作为虚基类出现多少次,只继承一个共享的基类子对象,共享的基类子对象称为虚基类,通过在派生列表中包含关键字virtual设置虚基类
17.3.6 虚基类的声明
通过用关键字virtual修改声明,将基类指定为通过虚继承派生,指定虚派生只影响从指定了虚基类的类派生的类,virtual说明符陈述了在后代派生类中共享指定基类的单个实例的愿望,任意可被指定为基类的类也可以被指定为虚基类,虚基类可以包含通常由非虚基类支持的任何类元素
17.3.7 特殊的初始化语义
通常,每个类只初始化自己的直接基类,在应用于虚基类的时候,这个初始化策略会失败,如果使用常规规则,就可能会多次初始化虚基类,类将沿着包含该虚基类的每个继承路径初始化,为了解决这个重复初始化的问题,从具有虚基类的类继承的类对初始化进行了特殊处理:在虚派生中,由最底层派生类的构造函数初始化虚基类,虽然由最底层派生类初始化虚基类,但是任何直接或间接继承虚基类的类一般也必须为该基类提供自己的初始化,只要可以创建虚基类派生类类型的独立对象,该类就必须初始化自己的虚基类,这些初始化只在创建中间类型的对象时使用
无论虚基类出现在继承层次中任何地方,总是在构造非虚基类之前构造虚基类