C++ Primer Plus(十五)——友元、异常和其它

1. 类声明的位置决定了类的作用域和可见性。类可见后,访问控制规则将决定程序对嵌套类成员的访问权限,包含嵌套类的类对于嵌套类并没有访问特权。

嵌套类、结构、枚举的作用域特征

声明位置包含它的类是否可以使用它从包含它的类派生而来的类是否可以使用它在外部是否可以使用
私有部分
保护部分
公有部分是,通过类限定符来使用

2. C++11抛弃了异常规范,它可能出现在函数原型和函数定义中,可包含类型列表,也可不包含,如:

double harm(double e) throw(bad_thing);
double marm(double) throw();

C++11支持一种特殊的异常规范,可使用新增的关键字noexcept指出函数不会引发异常。

3. 程序进行栈解退以回到能够捕获异常的地方时,将释放栈中的自动存储型变量。

4. 虽然throw-catch 机制类似于函数参数和函数返回机制,但还是有些不同之处。

(1)将函数控制权交到第一个包含能捕获相应异常的try-catch组合

(2)引发异常时总是创建一个临时拷贝,即使异常规范和catch块中指定的是引用。为何使用引用呢?不是已经生成副本了么?那是因为基类引用可以执行派生类对象,即在异常规范中只需列出一个基类引用,它将与任何派生类对象匹配。可以创建捕获对象而不是引用的处理程序。在catch语句中使用基类对象时,将捕获所有派生类对象,但派生特性将被剥去,因此将使用虚方法的基类版本。

如果有一个异常类继承层次结构,应这样排序catc块,将捕获位于层次结构最下面的异常类的catch语句放在最前面,将捕获基类异常的catch语句放在最后面。

5. C++异常:

对于使用new导致的内存分配问题,C++的处理方式是让new引发bad_alloc异常,它从exception派生而来。C++标准提供一种标记开关,其用法如下:

int *pi = new (std::nothrow) int; //失败返回空指针
int *pa = new (std::nowthrow) int[500]; //失败抛出异常

6. 未捕获异常不会导致程序立即终止,而是首先调用函数 terminate( )。在默认情况下,terminate将调用abort( )函数。可以调用set_terminate( )函数来指定terminate应调用的函数:

// 以下函数包含在 exception 中

typedef void (*terminate_handler)();
terminate_handler set_terminate(terminate_handler f) throw(); //c++98
terminate_handler set_terminate(terminate_handler f) noexcept(); //c++11

void terminate(); //c++98
void terminate() noexcept; //c++11

7. 意外异常,程序将调用unexpected( )函数,这个函数将调用terminate( ),后者在默认情况下将调用unexpected函数,若要修改unexpected行为,则可以使用set_unexpected( )函数:

// 以下函数包含在 exception 中

typedef void (*unexpected_handler)();
unexpected_handler set_terminate(unexpected_handler f) throw(); //c++98
unexpected_handler set_terminate(unexpected_handler f) noexcept(); //c++11

void unexpected(); //c++98
void unexpected() noexcept; //c++11

set_unexpected( )函数可以:

(1)通过调用terminate( )(默认行为)、abort( )或exit( )来终止程序

(2)引发异常,引发异常的结果取决于unexpected_handler函数所引发的异常以及引发异常的函数的异常规范:

        (1) 如果新引发的异常由原来的异常规范匹配,则程序从那里开始正常处理,即寻找和新引发异常匹配的catch块,这种方法将用预期的异常取代意外异常。

        (2) 如果新引发的异常与原来的异常规范不匹配,且异常规范中没有包括 std::bad_exception 类型,则程序将调用terminate( )。

        (3) 如果新引发的异常与原来的异常规范不匹配,且原来的异常规范包含了 std::bad_exception 类型,则不匹配的异常将被 std::bad_exception 异常取代。

8. RTTI(Runtime Type Identification)运行阶段类型识别,只适用于包含虚函数的类,原因在于只有对于这种类层次结构,才应该将派生类对象赋给基类指针。C++有三个支持RTTI的元素:

(1)dynamic_cast:它回答了“类型转换是否安全”的问题,并使用一个指向基类的指针来生成派生类的指针,否则,该运算符将返回0——空指针。也可以将dynamic_cast用于引用,其用法稍微有些不同:没有空指针对应的引用值,因此无法使用特殊的引用值来指示失败。当请求不正确时,dynamic_cast将引发bad_cast异常,这种异常是从exception类派生而来,它是在头文件typeinfo中定义的。

(2)type_id:它用来确定两个对象是否为同种类型,接受两种参数:类型、结果为对象的表达式,返回一个type_info对象,type_info类重载了 == 和 != 运算符,以便可以使用这些运算符进行类型比较。如果表达式是空指针,则程序将引发bad_typeid异常。type_info类的实现随厂商而异,但包含一个name( )成员,该函数返回一个随实现而异的字符串,通常是类的名称。

(3)type_info结构存储了相关特定类型的信息。

即使编译器支持RTTI,在默认情况下,它也有可能关闭这个特性。如果该特性被关闭,程序可能仍能通过编译,但将出现运行阶段错误,在这种情况下,应查看文档或菜单选项。

9. 类型转换运算符:
(1)dynamic_cast:用于将派生类指针转换为基类指针从而确保可以安全的调用虚函数,使用dynamic_cast进行转换的,基类中一定要有虚函数,否则编译不通过

(2)const_cast:只能改变值的 const 或 volatile 属性,也就是说type_name和expression类型必须相同。const_cast不是万能的,它可以修改指向一个值的指针,但修改const值的结果是不确定的。

(3)static_cast:只有type_name可被隐式转换为expression所属类型或expression可被隐式转换为type_name属性类型时,这种转换才是合法的。

(4)reinterpret_cast:用来处理无关类型之间的转换,它会产生一个新的值,这个值会有与原始参数(expressoin)有完全相同的比特位。

转载于:https://my.oschina.net/shou1156226/blog/867783

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值