您的位置:首页 > 编程语言 > C语言/C++

C++特殊工具与技术之RTTI

2014-10-09 00:32 169 查看
类型识别分为两种:一种以编译时类型识别,一种是运行时类型识别

编译时类型识别:static_cast;

运行时类型识别(RTTI),C++通过下面连个操作符提供RTTi;

1)dynamic_cast操作符,将基类类型的指针或者引用安全地转换为派生类型的指针或者引用;

2)typeid操作符,返回指针或者引用所指对象的实际类型。

注意:若想要实现运行时类型识别,则要求其使用类型为 至少带有一个虚函数的类。对于其他类型,返回静态(即编译时)类型的信息。


为叙述方便,我们先把所用的类的代码写出,其中Animal为基类,Cat、Dog类为其派生类;

class Animal
{
public:
virtual ~Animal(){ }
virtual void run()
{ cout<< "test" << endl; }
};

class Cat:public Animal
{
public:
void run()
{ cout << "Cat..." << endl;  }
};

class Dog:public Animal
{
public:
void run()
{  cout << "Dog.." << endl; }
};


一、static_cast(静态类型转换)的示例代码如下:

//static_cast发生在编译期间
#include <iostream>
#include <string>
#include <vector>
using namespace std;

int main(int argc, const char *argv[])
{
Animal *base;
Cat c;
Dog d;
base = &c;

Cat *pc = static_cast<Cat*>(base);
pc->run();//Cat...

Dog *pd = static_cast<Dog*>(base);
pd->run();//Cat..打印的是实际指向的Cat对象
return 0;
}


注意:static_cast发生在编译期间,如果转化失败,那么会产生编译错误;若果编译成功,那么则转化成功。但是static_cast仍具有一定风险,尤其是向下塑形时。将Base*(基类指针)转化为Deriverd*(派生类指针)时,指针可以转化,但是指针未必指向Derived对象。


二、dynamic_cast(动态运行转换)示例代码如下:

转换引用:

//转换引用
int main(int argc, const char *argv[])
{
Cat c;
Dog d;
Animal &base = c;//引用时必须初始化

Cat &pc = dynamic_cast<Cat&>(base);
cout << &pc << endl;
//test_result 0xbfebb0
Dog &pd = dynamic_cast<Dog&>(base);
cout << &pd << endl;
//test_result  bad_cast 与指针不同
return 0;
}


转换指针:

//转换指针
int main(int argc, const char *argv[])
{
Cat c;
Dog d;
Animal *base = &c;

Cat *pc = dynamic_cast<Cat*>(base);
cout << pc << endl; //打印指针的地址
//test_result oxbf94b98c
Dog *pd = dynamic_cast<Dog*>(base);
cout << pd << endl;
//test_result 0 //转化未成功
return 0;
}


注意:与dynamic_cast一起使用的指针必须是有效的--它必须为NULL,或者指向一个对象


dynamic_cast的具体实现:
1、dynamic_cast涉及运行时类型检查。如果绑定到引用或者指针的对象不是目标类型的对象 ,则dynamic_cast失败;

a)若是转换到指针类型 的dynamic_cast失败, 则dynamic_cast的结果为 0

b)若是转换到引用类型 的dynamic_cast失败, 则抛出一个 bad_cast类型的异常

步骤:dynamic_cast操作符一次执行两次操作;
1:首先验证被请求的转换是否有效;
2、在转换有效的情况下,操作符才实际进行转换。


C++primer 4th给出了使用dynamic_cast操作符的标准实践

//指针情况、
if(Derived *derivedPtr = dynamic_cast<Derived*>(basePtr)
{
//转化成功
}
else
{
//失败处理
}


引用情况:

//引用情况
try
{
const Derived &d = dynamic_cast<const Derived&>(b);
//成功情况
}
catch(bad_cast)
{
//失败处理
}


这段代码的逻辑是非常严密的:

Derived *derivedPtr 的作用域只存在于if语句中


不可能在dynamic_cast和测试转换结果之间插入代码,因此不可能在测试转换成功之前使用derivedPtr。


三、typeid运行时类型转换;

typeid的作用机制和dynamic_cast类似。示例代码如下:

int main(int argc, const char *argv[])
{
Cat c;
Dog d;
cout << typeid(string).name() << endl;
//类型名
cout << typeid(c).name() << endl;//3Cat
cout << typeid(d).name() << endl;//3Dog
Animal a;
cout << typeid(a).name() << endl;//6Animal
Animal *pa = &c;
cout << typeid(*pa).name() << endl;//3Cat

return 0;
}


只有当typeid的操作数满足以下两个条件时,才返回动态类型信息,
a)带有虚函数;
b)是类类型的对象。
另外,测试指针(相对于指针指向的对象)返回指针的静态的、编译时的类型。


RTTI的实例:C++ RTTI的使用
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: