运行时类型识别(RTTI)与动态类型转换原理(reinterpret_cast const_cast static_cast dynamic_cast)
来源:互联网 发布:乌鸦森林之谜3mac 编辑:程序博客网 时间:2024/06/05 04:46
RTTI的三个作用
(1)配合typeid操作符的实现
(2)实现异常处理中catch 的匹配过程
(3)实现动态类型转换dynamic_cast
1.typeid操作符的实现
(1)静态类型
使用typeid关键字来获取对象类型的信息,返回值是const std::type_info&
#include<iostream>using namespace std;#include<assert.h>struct B{}b,c;struct D:B{}d;void main(){const std::type_info& tb= typeid(b);const std::type_info& tc= typeid(c);const std::type_info& td= typeid(d);assert(tb == tc);//相同类型assert(&tb == &tc);//引用也是相同的对象assert(tb != td);//b d类型不相同assert(&tb != &td);// b , d的引用也不相同}
(二)动态类型的情形
typeid的操作数的引用是一个动态类(含有虚函数的类)类型时,返回值是被引用对象对应类型的类型信息对象
#include<iostream>#include<typeinfo>#include<assert.h>using namespace std;struct B{virtual void foo(){}};struct C{virtual void bar(){}};struct D:B, C{};int main(){D d;B& rb = d;C& rc = d;assert(typeid(rb) == typeid(d));//rb的引用类型与d相同assert(typeid(rb) == typeid(rc));//rb的引用类型与rc的引用类型相同}
如果表达式的类型是类类型而且至少包含一个虚函数,typeid返回表达式的动态类型,需要在运行时计算,否则typeid操作符将会返回表达式的静态类型,在编译时计算
#include<iostream>#include<typeinfo>using namespace std;class BaseA{};class DerivedA:public BaseA{};class BaseB{virtual void fun(){}};class DerivedB:public BaseB{};void main(){cout<<"-----直接处理类名--------"<<endl;cout<<typeid(BaseA).name()<<endl;cout<<typeid(DerivedA).name()<<endl;cout<<typeid(BaseB).name()<<endl;cout<<typeid(DerivedB).name()<<endl;cout<<"-----基类不含虚函数------"<<endl;BaseA baseA;DerivedA derivedA;cout<<typeid(baseA).name()<<endl;cout<<typeid(derivedA).name()<<endl;BaseA *pa;pa = &baseA;cout<<typeid(*pa).name()<<endl;cout<<typeid(pa).name()<<endl;pa = &derivedA;cout<<typeid(*pa).name()<<endl;cout<<typeid(pa).name()<<endl;cout<<"---基类含有虚函数---"<<endl;BaseB baseB;DerivedB deriveB;cout<<typeid(baseB).name()<<endl;cout<<typeid(deriveB).name()<<endl;BaseB *pb;pb = &baseB;cout<<typeid(*pb).name()<<endl;cout<<typeid(pb).name()<<endl;pb = &deriveB;cout<<typeid(*pb).name()<<endl;cout<<typeid(pb).name()<<endl;}
(1)当typeid 操作符的操作数是不带有虚函数的类类型时,typeid操作符会指出操作数的类型,而不是底层对象的类型
(2)如果typeid 操作符的操作数是至少包含一个虚函数的类类型时,并且该表达时是一个基类的引用,则typeid操作符指出底层对象的派生类类型
显式转换:
显示转换也称为强制类型转换(cast).包含以下强制类型转换的操作符
(1)static_cast
(2)dynamic_cast
(3)const_cast
(4)reinterpret_cast
转换的形式为:
cast_name<type>(expression)
cast_name为上述操作符的任意一个
type 为目标类型
expression 为被强制转换的表达式类型
(一)static_cast
(1)编译器隐式执行的任何类型转换都可以由static_cast来完成
#include<iostream>using namespace std;int main(){double d = 97.0;int i = static_cast<int>(d);cout<<i<<endl;}
(2)类层次之间上行/下行转换可以由static_cast 显式完成
但是(下行转换)把基类指针或引用转换为子类指针或者引用,由于没有动态类型检查,所以是不安全的(下行转换是不安全的)
#include<iostream>#include<typeinfo>using namespace std;class Base{};class Derived:public Base{};int main(){ Base *b = new Base; cout<<typeid(b).name()<<endl; Derived *c; c = static_cast<Derived*>(b); cout<<typeid(c).name()<<endl;}
运行结果:
C++基本类型的指针之间不含有隐式类型转换
(二)dynamic
cast_name<type>(expression)
作用:把expression 转换为type类型的对象
type 必须是类的指针,引用或者void*
如果type是指针类型,那么expression也是指针类型
如果type是引用类型,那么expression也是引用类型
dynamic_cast 涉及类型安全检查,dynamic_cast运行时类型检查,需要运行时类型信息,而这个信息存储在类的虚函数表中,只有定义了虚函数的类才有虚函数表,对于没有虚函数表的类使用会导致dynamic_cast 编译错误
如果绑定到引用或者指针的对象类型不是目标类型,则dynamic_cast失败
如果转换到指针类型的dynamic_cast失败,则dynamic_cast的结果为0
如果转换到引用类型的dynamic_cast失败,则抛出一个bad_cast的异常
可以在执行期决定真正的类型
如果下行转换是安全的(基类的指针或者引用确实指向一个派生类的对象),这个运算符就会传回转型过的指针
如果不安全,就传回空指针
进行上行转换与static_cast效果相同
进行下行转换时,dynamic_cast有类型的检查功能, 比static_const 更加安全
接下来下面的例子更好的理解dynamic_cast
#include<iostream>#include<typeinfo>using namespace std;class Base{public:Base():b(1){}virtual void foo(){}int b;};class Derived:public Base{public:Derived():d(2){}int d;};int main(){ Base *pb = new Derived; Derived *pd1 = static_cast<Derived*>(pb); cout<<pd1->b<<endl; cout<<pd1->d<<endl; Derived *pd2 = dynamic_cast<Derived*>(pb); cout<<pd2->b<<endl; cout<<pd2->d<<endl;}
运行结果:
分析:
Pd1和pd2是一样的,如果对这两个指针执行Derived类型的任何操作都是安全的,所以编译正常,运行正常,输出结果 正确
如果改为以下:
#include<iostream>#include<typeinfo>using namespace std;class Base{public:Base():b(1){}virtual void foo(){}int b;};class Derived:public Base{public:Derived():d(2){}int d;};int main(){ Base *pb = new Base;//改为指向base类型 Derived *pd1 = static_cast<Derived*>(pb); cout<<pd1->b<<endl; cout<<pd1->d<<endl;/* Derived *pd2 = dynamic_cast<Derived*>(pb); cout<<pd2->b<<endl; cout<<pd2->d<<endl; */}
结果:分析:
Pd1是一个指向B对象的指针,对它进行D类型操作时,是不安全的,输出的d
的值就是一个垃圾值,但是static_cast没有类型安全检查,所以程序正常运行
#include<iostream>#include<typeinfo>using namespace std;class Base{public:Base():b(1){}virtual void foo(){}int b;};
class Derived:public Base{
public:
Derived():d(2){}
int d;
};
int main()
{
Base *pb = new Base;
/*Derived *pd1 = static_cast<Derived*>(pb);
cout<<pd1->b<<endl;
cout<<pd1->d<<endl;*/
Derived *pd2 = dynamic_cast<Derived*>(pb);
cout<<pd2->b<<endl;
cout<<pd2->d<<endl;
}分析因为是不安全的,所以dynamic_cast会返回一个空指针,对空指针进行操作,就会发生异常
问题:
如果B中没有虚函数,会发生什么情况?
#include<iostream>#include<typeinfo>using namespace std;class Base{public:Base():b(1){}//virtual void foo()//{}int b;};class Derived:public Base{public:Derived():d(2){}int d;};int main(){ Base *pb = new Derived; Derived *pd1 = static_cast<Derived*>(pb); cout<<pd1->b<<endl; cout<<pd1->d<<endl;/* Derived *pd2 = dynamic_cast<Derived*>(pb); cout<<pd2->b<<endl; cout<<pd2->d<<endl; */ }
编译结果:正常编译
运行结果:正常运行
static_cast没有必须有虚函数表的限制,所以正常编译,正常运行
如果改为下面代码:
#include<iostream>#include<typeinfo>using namespace std;class Base{public:Base():b(1){}//virtual void foo()//{}int b;};class Derived:public Base{public:Derived():d(2){}int d;};int main(){ Base *pb = new Derived; /*Derived *pd1 = static_cast<Derived*>(pb); cout<<pd1->b<<endl; cout<<pd1->d<<endl;*/ Derived *pd2 = dynamic_cast<Derived*>(pb); cout<<pd2->b<<endl; cout<<pd2->d<<endl; }
编译结果:
分析:dynamic_cast运行时类型安全检查需要运行时类型信息,而这个信息存储在类的虚函数表中,只有定义了虚函数的类才有虚函数表,所以就会编译错误
#include<iostream>using namespace std;class Base1{virtual void f1(){cout<<"Base1::f1"<<endl;}};class Base2{virtual void f2(){cout<<"Base2:f2"<<endl;}};class Derived:public Base1, public Base2{void f1(){cout<<"Derived::f1"<<endl;}void f2(){cout<<"Derived::f2"<<endl;}};int main(){Base1 *pb= new Derived;Derived *pd1 = dynamic_cast<Derived*>(pb);Derived *pd2 = static_cast<Derived*>(pb);Base2 *pb1 = dynamic_cast<Base2*>(pb);Base2 *pb2 = static_cast<Base2*>(pb);}
运行结果:
分析:对于多重继承,如果pb 真的指向Derived, 使用dynamic_cast 或者 static_cast都可以,但是如果要转化Base1 为其兄弟类Base2, 必须使用dynamic_cast,
使用static_cast无法编译
(三)const_cast
将转换表达式的const 性质
只有用const_cast才能将const性质转换掉,除了添加和删除const 特性,用const_cast符来执行其它任何类型的转换都会引起编译错误
const double val = 0.1;double *ptr = const_cast<double*>(&val);
(四)reinterpret_cast
显式强制类型转换用圆括号实现
int *p;char *ptr = (char*)p;效果与使用reinterpret相同char *pc = reinterpret_cast<char*>(p);
- 运行时类型识别(RTTI)与动态类型转换原理(reinterpret_cast const_cast static_cast dynamic_cast)
- c++ RTTI c++强制类型转换:dynamic_cast、const_cast 、static_cast、reinterpret_cast
- C++动态转换类型static_cast,dynamic_cast,reinterpret_cast和const_cast探究
- static_cast dynamic_cast const_cast reinterpret_cast 类型转换
- C++ - 类型转换 static_cast, dynamic_cast, reinterpret_cast, const_cast
- 类型转换static_cast dynamic_cast const_cast reinterpret_cast
- static_cast, const_cast, dynamic_cast, 和reinterpret_cast 类型转换
- static_cast、dynamic_cast、reinterpret_cast和const_cast 类型转换
- C++类型转换 static_cast, dynamic_cast, reinterpret_cast, const_cast
- C++类型转换:static_cast、const_cast、dynamic_cast、reinterpret_cast
- C++类型转换 static_cast、dynamic_cast、const_cast、reinterpret_cast
- C++类型转换: static_cast const_cast reinterpret_cast dynamic_cast
- 类型转换-static_cast、dynamic_cast、reinterpret_cast、const_cast探讨
- reinterpret_cast,static_cast,dynamic_cast,const_cast类型转换
- xxx_cast类型转换static_cast/const_cast/reinterpret_cast/dynamic_cast
- 动态运行时类型识别与显示转换(typeid(a);static_cast<type>(expression);dynamic_cast<type>(expression);const_cast<typ
- C++ 类型转换(static_cast、dynamic_cast、const_cast、reinterpret_cast)
- 【C++】强制类型转换(static_cast,reinterpret_cast,const_cast,dynamic_cast,explicit)
- hihocoder 1093 : 最短路径·三:SPFA算法
- 合并两个整数集合,并排序---京东2017秋招笔试
- arcgis10.2导入数据到postgresql9.1
- 委托
- IDEA 及 Gradle 使用总结
- 运行时类型识别(RTTI)与动态类型转换原理(reinterpret_cast const_cast static_cast dynamic_cast)
- 第四周
- 使用webpack 手动创建新react项目
- 系统学习深度学习(三十六)--G-CNN
- HDU 5701中位数计数
- 计算机体系结构--中央处理器
- 解决linux环境mysql的sql语句严格区分大小写问题
- 展示数据后某一条数据置顶显示的方法
- 在NebBean中配置常用插件-调试/预览页面/打开项目文件夹/JS代码提示