C++学习-Day-30

一、友元类

类并非只能拥有友元函数,也可以将类作为友元,在这种情况下,友元类的所有方法都可以访问原始类的私有成员和保护成员。那么什么时候使用友元类呢?当两个类既不是is-a和has-a关系,但是两者存在某一关系时可以考虑友元类,下面的语句使Remote成为友元类:

friend class Remote; 

友元类声明可以在公有、私有或保护部分,其所在位置无关紧要。

有时候我们不需要将整个类成为友元类,而只需要让特定的类成员成为另一个类的友元,但是这样做稍微有点麻烦,我们需要小心排列各种声明和定义。比如我们需要将一个类(Remote)的某一成员函数成为另一个类(Tv)的友元,只需要在Tv中将其函数原型声明为友元,语句如下:

class Tv {friend void Remote::name();…}

但是要让编译器能够理解该语句,必须让Remote在Tv之前声明。但是Remote中有可能包含了Tv类,要避开这种循环依赖我们需要使用前向声明。为此,我们需要在Remote类的定义前插入下面语句:

class Tv;//forward declaration
class Remote{};
class Tv{ friend void Remote::name();…};

共同的友元。有时候我们要让函数访问两个类的私有数据,从逻辑上来看,这样的函数应该是每个类的成员函数,但这是不可能的。它可以是一个类的成员函数,另一个类的友元函数,但有时将函数作为两个类的友元更合理。

二、嵌套类

在C++中可以将类声明放在另一个类中,在另一个类中声明的类被称为嵌套类,它通过提供新的类型类作用域来避免名称混乱。对类进行嵌套和包含不同,包含意味着将类对象作为另一个类的成员,而对类进行嵌套并不创建类对象,只是定义了一种类型,该类型仅在包含嵌套类声明的类中才有效。嵌套类作用域根据其声明位置(私有、保护、公有)不同而不同。

三、异常

程序有时会遇到运行阶段错误,导致程序无法正常地运行下去,通常,程序员都会去试图预防这种意外情况,C++异常为处理这种情况提供了一种功能强大而灵活的工具。

异常终止。调用abort()或exit(),abort()向标准错误流发送消息(程序异常终止),然后终止程序并返回一个值,exit()刷新文件缓冲区但不显示消息。

返回错误码。一种比异常终止更灵活的方式是使用函数返回值来指出问题。

异常机制。对异常的处理包括三个部分:1)引发异常2)使用处理程序捕获异常3)使用try块。

假设有一个异常类层次结构,并要分别处理不同的异常类型,则使用基类引用能够捕获任何异常对象,而派生类对象只能捕获它所属的类和从它派生出的类对象。

有时候我们不知道会发生哪些类型的异常,在这种情况下,我么可以使用省略号来捕获异常。

exception类。C++异常的主要目的是为了设计容错程序提供语言支持,以免事后采取一些严格的错误处理方式。较新的C++编译器将异常合并到语言中,为了支持该语言,exception头文件定义了exception类,C++可以将它用作其它异常类的基类。有一个名为what()的虚拟成员函数,它返回一个字符串,该字符串的特征随实现而异。由于它是一个虚方法,因此我们可以重新定义它。

异常被引发后,在两种情况下会导致问题:1)在带异常规范的函数中引起则必须与规范列表中异常类型匹配,否称为意外异常2)如果异常不是在函数中引发的,则必须捕获它,如果没有被捕获(在没有try块或没有匹配catch块时),则异常被称为未捕获异常,在默认情况下这将导致程序终止,然而我们可以修改这一行为。未捕获异常不会立刻导致程序终止,它会先调用terminate(),在默认情况下terminate()调用abort()函数,我们可以指定terminate()应调用的函数(不是abort(函数)来修改这一行为。为此我们可以调用set_terminate()函数,terminate()和set_terminate()函数都是在exception头文件中声明的。

四、RTTI

RTTI是运行阶段类型识别的简称。RTTI旨在为程序在运行阶段确定对象的类型提供一种标准方式,很多类库已经为其对象提供了实现这种功能的方式,但由于C++内部并不支持,因此各个厂商的机制通常互不兼容,创建一种RTTI语言标准将使得未来的库能够彼此兼容。

C++有3个支持RTTI的元素:1)如果可能的话,dynamic_cast运算符将使用一个指向基类的指针来生成一个指向派生类的指针,否则该运算符返回一个空指针;
2)typeid运算符返回一个指出对象的类型的值;
3)type_info结构存储了有关特定类型的信息。

注意:只能将RTTI用于包含虚函数的类层次结构,原因在于只有对于这种类层次结构,才应该将派生对象的地址赋给基类指针。

下面我们来详细看看这3种元素:

  1. dynamic_cast运算符:通常我们想知道类型的原因在于知道了类型后就可以知道调用特定的方法是否安全,要调用方法并不一定要完全匹配,因此我们知道“类型转换是否安全”比知道“指针指向的是哪种类型”更通用,也更有用。其语法为:

Super * pm=dynamic_cast<Super *>(pg);

其中pg指向一对象,该语句指出指针pg是否能安全地转换为Super*,如果可以则运算符返回对象的地址,否则返回一个空指针。
3. typeid运算符使得能够确定两个对象是否为同种类型。typeid运算符返回一个队type_info对象的引用,其中type_info是在头文件typeinfo中定义的一个类。type_info对象有个name()成员能返回一个随实现而异的字符串,通常为类名。

五、类型转换运算符

C语言中类型转换太过松散(限制不严格),因此C++创始人添加了4个类型转换运算符,使转换过程更规范:

  1. dynamic_cast:使得能够在类层次结构中进行向上转换。
  2. const_cast:改变值为const或volatile,其语法与dynamic_cast相同。除了const或volatile特征可以不同外,typename和expression类型必须相同。
  3. static_cast:static_cast<type_name>(expression)仅当type_name可以隐式地转换为expression所属的类型或expression可以隐式地转换为type_name所属的类型时上述转换才是合法的。
  4. reinterpret_cast:用于天生危险的类型转换。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值