第十五章 友元类&嵌套类&异常&RTTI&类型转换运算符

友元类

和友元函数一样,友元类具有原始类的访问权限,可以访问其私有成员和保护成员。友元类的关系不同于is-a或has-a关系,友元类可以让看起来互无关系的两个类具有关系,比如遥控器和电视机。

声明友元类的位置无关紧要,在private或public都可以,但是由于友元类或访问原始类的对象,所以原始类的声明必然在友元类之前,面对更复杂的情况可以使用前置声明


有些时候并不需要整个类都声明为友元,只将部分函数声明问友元成员函数。注意使用域解析符。

friend void Remote::set_channel(Tv& tv,int c);

假设TV类就有这样一个友元成员函数,这样它就要首先Remote是一个类才能正确编译,所以Remote类应在TV类之前,但是set_channel又使用了TV类的私有成员,这代表着TV类又必须在Remote类之前。而这是不可能做到的。

使用前置声明避免问题发生

class TV;
class Remote{};
class TV{};

不能反过来声明,因为TV类声明的是友元成员函数,它必须看到这个成员函数的声明才行。前置声明只负责告诉编译器这是一个类,而对类中的方法一无所知,直到它的定义出现。

假如Remote类中也要使用TV类中的方法怎么办?

答案是暂时在Remote类中申明函数原型,然后再TV类后面定义。

class TV;
class Remote{};
class TV{};

return-type Remote::function(...){}

使用inline关键字可以根据需要变成内联函数。

嵌套类

在类中声明结构,类都是嵌套类。

嵌套类最重要的是认识到他的访问权限。

  • 首先要看类是否可见。
    • 如果嵌套类再私有字段,那么只有声明它的类知道它的存在。
    • 保护字段则是声明它的类和派生类,外部不可见。
    • 公有字段则都可见。
  • 之后看嵌套类的访问控制
    • 对于嵌套类外面的部分,都看作外部。比如说声明它的类可见嵌套类,但依旧不能访问嵌套类的私有字段和保护字段。因为对于嵌套类来说,声明它的类已经是外部了。

异常

  • 将对象作为异常类型,我们可以构造一个异常类(STL就是这样做的)能够更方便我们关系异常的行为。再触发异常时将该类的对象抛出。
  • 栈解退:不同于函数返回,再函数抛出异常后,程序会直接跳到第一个匹配异常对象的catch块,将在这其中创建的对象全部释放掉,对于自定义类程序会自动调用析构函数。
  • 异常总是会创建一个临时拷贝的异常对象,这是因为在函数结束的时候,这个异常对象同样也会被释放,所以创建副本给调用异常处理程序是必要的。但是我们依然能看到catch块后的异常匹配类型依旧是引用,这是为了让派生类对象和基类匹配。
  • 如果你想具体的触发某种异常类,则catch块的配列顺序应该与派生顺序相反,否则它会率先和基类对象匹配而输出基类的信息。
  • 使用catch(…)来接收任何的异常。

RTTI(运行阶段类型识别)

RTTI:Runtime Type Identification,运行阶段识别,旨在为程序在运行阶段确定对象类型提供一种标准方式。

如果我们希望程序在运行时候调用对应的函数,在类层次结构中所有成员都拥有虚函数,则不需要RTTI的支持。但派生对象可能包含不是继承而来的方法,或者想要调试跟踪目标对象,RTTI提供了支持。

C++提供了三个支持RTTI的元素

  • 使用dynamic_cast运算符。
  • typeid运算符
  • type_info结构存储信息。

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

dynamic_cast运算符

dynamic_cast指出“是否可以安全地将对象的地址赋给特定类型的指针”,用法为:

dynamic_cast<type-name> (expression)

dynamic_cast类似于一种类型转换,它可以判断是否可以安全的在基类和派生类指针之间转换,如果安全——派生类指针赋值给基类,那么将该指针转换为基类或间接基类指针,如果不安全——基类转为派生类,则返回null。

对于引用,由于没有类似于空指针的空引用,所以引用在转换失败时会抛出bac_cast异常。

typeid和tpye_info

typeid运算符返回一个type_info的引用,而type_info重载了==和!=,所以你可以很方便的判断两个类类型是否相同。

typeid(Magnificent)==typeid(*pg)

如果pg是一个空指针,将引发bad_typeid异常。

你可以调用type_info的方法来访问查看类型的信息,比如name()会打印类的名字。

类型转换运算符

  • dynamic_cast
  • const_cast
  • static_cast
  • reinterpret_cast

const_cast

const_cast<type-name>(expression) //type-name must same as expression's type

const_cast可以让类型在const或volatile之间转换,const_cast只能在指针或引用之间使用。

注意,const虽然可以改变指针const的标签,但是假如指针指向的值是常量,那么你依旧无法改变该值。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值