15. 友元、异常和其他
1. 友元
友元类、友元函数、类彼此成为对方的友元

共同的友元

2. 嵌套类
在另一个类中声明的类 被称为嵌套类,通过提供新的类型类作用域来避免名称混乱。

模板中也可以嵌套类
3. 异常
1.调用abort()


2.返回错误码


3.异常机制
异常处理三个组成部分





4.将对象 用作异常类型



6.栈解退
- C++通常是如何处理函数调用和返回的。
- C++通常通过将信息放在栈(参见第9章)中来处理函数调用。具体地说,程序将调用函数的指令的地址(返回地址)放到栈中。当被调用的函数执行完毕后,程序将使用该地址来确定从哪里开始继续执行。另外,函数调用将函数参数放到栈中。在栈中,这些函数参数被视为自动变量。如果被调用的函数创建了新的自动变量,则这些变量也将被添加到栈中。如果被调用的函数调用了另一个函数,则后者的信息将被添加到栈中,依此类推。当函数结束时,程序流程将跳到该函数被调用时存储的地址处,同时栈顶的元素被释放。因此,函数通常都返回到调用它的函数,依此类推,同时每个函数都在结束时释放其自动变量。如果自动变量是类对象,则类的析构函数(如果有的话)将被调用。
- 现在假设函数由于出现异常(而不是由于返回)而终止,则程序也将释放栈中的内存,但不会在释放栈的第一个返回地址后停止,而是继续释放栈,直到找到一个位于try块(参见图15.3)中的返回地址。随后,控制权将转到块尾的异常处理程序,而不是函数调用后面的第一条语句。这个过程被称为栈解退。引发机制的一个非常重要的特性是,和函数返回一样,对于栈中的自动类对象,类的析构函数将被调用。然而,函数返回仅仅处理该函数放在栈中的对象,而how语句则处理ry块和how之间整个函数调用序列放在栈中的对象。如果没有栈解退这种特性,则引发异常后,对于中间函数调用放在栈中的自动类对象,其析构函数将不会被调用。
7.其他异常特性
另一个不同之处是,引发异常时编译器总是创建一个临时拷贝,即使异常规范和catch块中指定的是引用。
提示:如果有一个异常类继承层次结构,应这样排列catch块:将捕获位于层次结构最下面的异常类的catch语句放在最前面,将捕获基类异常的catch语句放在最后面。


8.exception

2.bad_alloc异常和new
对于使用new导致的内存分配问题,C++的最新处理方式是让new引发bad_alloc异常。


9.异常 类 和继承
异常、类和继承以三种方式相互关联。首先,可以像标准C++库所做的那样,从一个异常类派生出另一个;其次,可以在类定义中嵌套异常类声明来组合异常;第三,这种嵌套声明本身可被继承,还可用作基类。
异常被引发后,在两种情况下,会导致问题。首先,如果它是在带异常规范的函数中引发的,则必须与规范列表中的某种异常匹配(在继承层次结构中,类类型与这个类及其派生类的对象匹配),否则称为意外异常(unexpected exception)。在默认情况下,这将导致程序异常终止(虽然C++1I摒弃了异常规范,但仍支持它,且有些现有的代码使用了它)。如果异常不是在函数中引发的(或者函数没有异常规范),则必须捕获它。如果没被捕获(在没有try块或没有匹配的catch块时,将出现这种情况),则异常被称为未捕获异常(uncaught exception)。在默认情况下,这将导致程序异常终止。然而,可以修改程序对意外异常和未捕获异常的反应。

4. RTTI
RTTI的工作原理:
C++有3个支持RTTI的元素

RTTI只适用于包含虚函数的类。
1.dynamic_cast



2.typeid运算符和type_info类

typeid运算符返回一个对type_info对象的引用,其中,type_info是在头文件typeinfo(以前为typeinfo.h)中定义的一个类。type_info类重载了==和!=运算符,以便可以使用这些运算符来对类型进行比较。








