写点什么

友元、异常和其他

作者:Maybe_fl
  • 2022-12-01
    陕西
  • 本文字数:1763 字

    阅读完需:约 6 分钟

友元、异常和其他



友元


友元被授予从外部访问类的私有部分的权限,但它们并不与面向对象的编程思想相悖;相反,它提高了共有接口的灵活性。比如之前提到的ostreamstring的实现,两者之间的关系用友元函数就可以解决。到底什么情况希望一个类成为另外一个来的友元呢?我们来看一个例子,有两个类,一个是Tv类和一个Remote类,分别表示电视机和遥控器


class Remote;class Tv{  public:  friend class Remote;  ...};
class Remote{ public: void set_mode(Tv& t) { ... }};
复制代码


两者之间的关系当然不是is-a关系,遥控器也不是电视机的一部分,也不是has-a关系,这个时候可能友元是最好来描述两者之间的关系。

嵌套类

在 C++中,可以将类声明放在另一个类中,被称为嵌套类。好处是可以通过提供新的类型类作用域避免名称混乱


class Queue{private:  struct Node{...};  Node* items;};
复制代码


若有一个此类的友元函数想使用这一个Node类型,其访问方式为


Queue::Node node
复制代码

异常

程序有时会遇到运行阶段错误,导致程序无法正常地运行下去,为了反馈这种异常,可以用的方法是异常情况时打印相关信息、返回错误码等;此外,传统的 C 语言数学库使用一个名为errno的全库变量,在函数调用完成后,通过检查该变量来查看异常情况。而C++提供了一个强大而灵活的工具:异常


其语法为:


class bad_hmean  //异常类{public:  double v1;  double v2;  string msge(){...};};

try{ ... if(...) throw bad_hmean(a,b) //抛出异常}catch (bad_hmean& bg) //捕获异常{ cout << bg.msge() << endl; break;}
复制代码


注意bgbad_hmean(a,b)的副本,而不是本身,因为函数执行完毕后,bad_hmean(a,b)将不复存在,编译器会创建一个临时拷贝。

bad_alloc 和 new

C++的new是由malloc的思想的基础上衍化而来,最开始的 new 借鉴了malloc的规则。malloc分配失败,会返回一个空指针。最开始的编译器(如 VC 6.0),也如果new失败,也会返回一个空指针。这时候的检测方式如下:


int* p = new int[SIZE];if(NULL == p){  cout << "bad_alloc" << endl;}
复制代码


但随着 C++语言的发展,C++的最新处理方式是让new引发bad_alloc异常。这时如果还是上述代码,在new失败的情况下,函数抛出了异常,但是没有被捕获,在默认情况下,函数也会异常终止。


由于很多代码都是使用这种方式。因此当前 C++标准提供了一种在失败时返回空指针的new,其用法如下:


int* p = new (std::nothrow)int[SIZE];if(NULL == p){  cout << "bad_alloc" << endl;}
复制代码


只需将核心代码改为上述这种方式即可。

RTTI

RTTI 是运行阶段类型识别(Runtime Type Identification)的简称。比如基类指针可以指向多种派生类,如何知道这个指针指向的是那种对象呢? RTTI 提供了解决方案。C++有三个支持 RTTI 的元素。

type_info

type_info是一个结构体存储了有关特定类型的信息,它重载了==和!=等运算符用于对类型进行比较。还有type_info::name()成员函数来输出类别信息。

typeid

typeid是运算符,他返回一个指向type_info的值。


int a = 0 ;double b = 0;
cout << typeid(a).name() << endl;cout << typeid(b).name() << endl;
if(typeid(a) == typeid(b)) cout << "a and b are the same type" << endl;else cout << "a and b are different types" << endl;
output:intdoublea and b are different types
复制代码


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


class Base {};class Derived : public Base {};
Base* pb1 = new Base();Base* pb2 = new Derived();cout << typeid(*pb1).name() << endl;cout << typeid(*pb2).name() << endl;
output:class Baseclass Base
复制代码


上述不包含虚函数的类无法表明基类指针到底指向哪一个派生类对象,RTTI只适用于包含虚函数的类


class Base {virtual void func(){};};
class Derived : public Base {virtual void func(){};};
Base* pb1 = new Base();Base* pb2 = new Derived();cout << typeid(*pb1).name() << endl;cout << typeid(*pb2).name() << endl;
output:class Baseclass Derived
复制代码

dynamic_cast

dynamic_cast运算符将使用一个指向基类的指针安全转换为一个指向派生类的指针。若不能安全转换,该运算符返回一个空指针。

用户头像

Maybe_fl

关注

还未添加个人签名 2019-11-11 加入

还未添加个人简介

评论

发布
暂无评论
友元、异常和其他_Maybe_fl_InfoQ写作社区