第十五章 友元 异常和其他
RTTI
RTTI是什么
RTTI是运行阶段类型识别,通过运行时类型识别,程序能够使用基类的指针或者引用来检查这些指针或者引用所指向的对象的实际派生类型。
RTTI的三个元素
dynamic_cast运算符
dynamic_cast概念:
dynamic_cast运算符能够将基类+的指针或引用安全的转换成派生类的指针或者引用
dynamic_cast语法:
dynam_cast<Type*>(pt);
dynamic_cast案例演示:
假设定义了如下类
#include<iostream>using std::cout;
using std::endl;class A
{
public:virtual void func1() { cout << "这是A的func1函数" << endl; }virtual void func2() { cout << "这是A的func2函数"; }
};
class B : public A
{
public:virtual void func1() { cout << "这是B的func1函数" << endl; }virtual void func2() { cout << "这是B的func2函数"; }void func3() { cout << "B的func3函数"; }
};
class C : public A
{
public:virtual void func1() { cout << "这是C的func1函数" << endl; }virtual void func2() { cout << "这是C的func2函数"; }
};
如何通过基类指针调用派生类的成员函数呢?
int main()
{A* p_a = new B;p_a->func3();return 0;
}
这样调用会直接报错,因为A类中没有func3函数,要使用B类方法必须要将指针转换成B类指针才可以
B* p_b = (B*)p_a; //c风格的强制类型转换,可能会导致错误p_b->func3()
强制类型转换可以将指针进行转换,但无法指出转换的安全性与合适性:就好别人传来一个指针,你需要确定这个是否为你想要转换的类型,这时使用dynamic_cast就非常有必要
B* p_b1 = dynamic_cast<B*>(p_a); // p_a指向的是B类型的对象,所以可以转换成功
if(p_b1 != nullptr) cout << "p_a实际是一个B类型" << endl;
else cout << "p_a不是B类型,转换失败" << endl;
对于引用类型转换失败,会报出一个异常,std::bad_cast。
A* pa_0 = new B;
A & pa_1 = * pa_0
try
{B & pb_0 = dynamic_cast< B& >(pa_1);cout << "pa_0 是B对象的引用 " << endl;
}
catch(std:bad_cast)
{cout << " pa_1 不是对象B的引用 " << endl;
}
typeid运算符
typeid运算符概念:
typeid运算符:拿到对象信息typeid就会返回一个常量对象的引用,这个常量对像是一个标准库类型type_info(类/类型)
typeid用法:
typeid(类名),typeid(结果为对象的表达式),typeid 常用于确定两个对象是否是同一类型。
案例演示
A* pa1 = new B;
B* pa2 = new B;if(typeid(pa1) == typeid(pa2)) cout << "yes" << endl;
else cout << "no" << endl;
注意不要把typeid用来识别指针,这样他只是识别定义时的类型,应该传递对象。
A* pa1 = new B;
B* pa2 = new B;if(typeid(*pa1) == typeid(*pa2)) cout << "yes" << endl;
else cout << "no" << endl;
在这里可以使用等号的原因是,type_info类重载了==和!=运算符,所以可以使用这些运算符来进行类型的比较
typeid().name()将返回实际类型
char a;
int b;
A * pa = new B;cout << typeid(*pa).name() << endl; // 返回class B
cout << typeid(a).name() << endl; // 返回char
cout << typeid(b).name() << endl; // 返回int