Runtime Type Identification(RTTI) RTTI的意图:提供一个在运行时决定对象类型的标准机制。 有3个元素支持RTTI:dynamic_cast、typeid、type_info 注意事项:RTTI只可用于有虚函数的类
dynamic_cast是最常用的RTTI操作符。 回答的问题:是否能将某个对象的地址安全地赋值给一个特定类型的指针;同时也回答了强制类型转换是否安全的问题 格式:
dynamic_cast(pt)
pt能否安全的类型转换(pt为Type或者pt为Type的继承类)为Type *,如果可以,则返回pg的地址;反之,返回0 也可以使用引用(应该不常用):
dynamic_cast(rg)
pt能否安全的类型转换(pt为Type或者pt为Type的继承类)为Type &,如果可以,则返回pg的地址;反之,引发bad_cast异常(在typeinfo头文件中)
typeid决定两个对象的类型是否相等。 typeid的返回值为:type_info
type_info定义在typeinfo头文件中 type_info重载了== and != 操作符,因此可以比较两个类型是否相等
格式:
typeid(Magnificent) == typeid(*pg)//返回True(类型相等) or False(类型不等)
bad_typeid异常:如果pg恰好是Null指针,则抛出bad_typeid异常,bad_typeid异常定义在typeinfo头文件中。 name()成员函数:type_info对象有成员函数name(),可以返回typeid(class)中class类的名称。 注意事项:如果发现使用typeid需要一长串if else,则要考虑使用dynamic_cast
转换格式:
const_cast < type-name > (expression)
要求:type-name和expression必须是同一种类型,他们只在const和volatile上存在区别,转换成功就赋值就行,转换失败则返回0 与常规类型转换的不同:常规类型转换可以转换为不同类型,但是const_cast不允许不同类型的转换 基本原则:不允许将定义为const的变量转换为非const类型。
格式:
static_cast < type-name > (expression)
当且仅当type-name类型可以隐式转换为expression类型,或反之,否则类型转换会报错,两者能互相转换 1.允许向上转换(继承类指针转换为基类指针) 2.允许向下转换(基类指针转换为继承类指针) 3.由于枚举类可以隐式转换为int,因此static_cast允许这类转换,并且允许将int类型转换为枚举类 4.允许将double转换为int,将int转换为double 5.允许将float转换为long,允许将long转换为float
格式:
reinterpret_cast < type-name > (expression)
可以将指针类型转换为能够容纳该指针类型的整型,反之不能转换。 不能将函数指针转换为数据指针
rtti.h
#pragma once #includeusing std::cout; #ifndef _RTTI1_H_ #define _RTTI1_H_ class Grand { private: int hold; public: Grand(int h = 0) : hold(h) {} virtual void Speak() const { cout << "I am a grand class!\n"; } virtual int Value() const { return hold; } }; class Superb : public Grand { public: Superb(int h = 0) : Grand(h) {} void Speak() const { cout << "I am a superb class!!\n"; } virtual void Say() const { cout << "I hold the superb value of " << Value() << "!\n"; } }; class Magnificent : public Superb { private: char ch; public: Magnificent(int h = 0, char c = 'A') : Superb(h), ch(c) {} void Speak() const { cout << "I am a magnificent class!!!\n"; } void Say() const { cout << "I hold the character " << ch << " and the integer " << Value() << "!\n"; } }; #endif
代码:main.cpp
#include#include #include #include"rtti1.h" #include using std::cout; using std::endl; /* 运行时类型识别:Runtime Type Identification(RTTI) RTTI的意图:提供一个在运行时决定对象类型的标准机制。 有3个元素支持RTTI:dynamic_cast、typeid、type_info 注意事项:RTTI只可用于有虚函数的类 */ Grand* GetOne(); void change(const int* pt, int n); int main() { /* dynamic_cast: dynamic_cast是最常用的RTTI操作符。 回答的问题:是否能将某个对象的地址安全地赋值给一个特定类型的指针;同时也回答了强制类型转换是否安全的问题 格式:dynamic_cast (pt) pt能否安全的类型转换(*pt为Type或者*pt为Type的继承类)为Type *,如果可以,则返回pg的地址;反之,返回0 也可以使用引用(应该不常用):dynamic_cast (rg) pt能否安全的类型转换(pt为Type或者pt为Type的继承类)为Type &,如果可以,则返回pg的地址;反之,引发bad_cast异常(在typeinfo头文件中) */ cout << "dynamic_cast***************************************************************" << endl; std::srand(std::time(0)); Grand* pg; Superb* ps; for (int i = 0; i < 5; i++) { pg = GetOne(); pg->Speak(); if (ps = dynamic_cast (pg)) //如果可以转换,则if条件判断为1,则执行ps->Say();反之,不执行 ps->Say(); } /* typeid and type_info: typeid: typeid决定两个对象的类型是否相等。 typeid的返回值为:type_info type_info: type_info定义在typeinfo头文件中 type_info重载了== and != 操作符,因此可以比较两个类型是否相等 typeid and type_info: 格式:typeid(Magnificent) == typeid(*pg)//返回True(类型相等) or False(类型不等) bad_typeid异常:如果pg恰好是Null指针,则抛出bad_typeid异常,bad_typeid异常定义在typeinfo头文件中。 name()成员函数:type_info对象有成员函数name(),可以返回typeid(class)中class类的名称。 注意事项:如果发现使用typeid需要一长串if else,则要考虑使用dynamic_cast */ cout << "typeid***************************************************************" << endl; for (int i = 0; i < 5; i++) { pg = GetOne(); cout << "Now processing type " << typeid(*pg).name() << ".\n"; pg->Speak(); if (ps = dynamic_cast (pg)) ps->Say(); if (typeid(Magnificent) == typeid(*pg)) cout << "Yes, you're really magnificent.\n"; } /* const_cast: 转换格式:const_cast < type-name > (expression) 要求:type-name和expression必须是同一种类型,他们只在const和volatile上存在区别,转换成功就赋值就行,转换失败则返回0 与常规类型转换的不同:常规类型转换可以转换为不同类型,但是const_cast不允许不同类型的转换 基本原则:不允许将定义为const的变量转换为非const类型。 */ cout << "const_cast***************************************************************" << endl; int pop1 = 38383; const int pop2 = 2000; cout << "pop1, pop2: " << pop1 << ", " << pop2 << endl; change(&pop1, -103);//转换了,因为pop1是非const类型 change(&pop2, -103);//没转换,因为pop2是const类型 cout << "pop1, pop2: " << pop1 << ", " << pop2 << endl; /* static_cast: 格式:static_cast < type-name > (expression) 当且仅当type-name类型可以隐式转换为expression类型,或反之,否则类型转换会报错,两者能互相转换 1.允许向上转换(继承类指针转换为基类指针) 2.允许向下转换(基类指针转换为继承类指针) 3.由于枚举类可以隐式转换为int,因此static_cast允许这类转换,并且允许将int类型转换为枚举类 4.允许将double转换为int,将int转换为double 5.允许将float转换为long,允许将long转换为float */ cout << "static_cast***************************************************************" << endl; Grand x = Grand(10);//基类对象 Grand * w = &x;//基类指针 Superb z = Superb(11);//继承类对象 Superb * pointer1 = &z; Superb * y = static_cast< Superb* >(w);//将基类指针转换为继承类指针 允许 y->Speak();//只是允许但是不推荐,因为转换为继承类指针后可以调用继承类的成员方法,而基类没有该成员方法,会引发异常 Grand * a = static_cast (pointer1);//将继承类指针转换为基类指针 a->Speak(); int varint1 = 99; double vardouble1 = 99.99; int var = static_cast (vardouble1); std::cout << "var = " << var << std::endl; double var1 = static_cast (varint1); std::cout << std::fixed <<"var1 = " << var1 << std::endl; /* reinterpret_cast: 格式:reinterpret_cast < type-name > (expression) 可以将指针类型转换为能够容纳该指针类型的整型,反之不能转换。 不能将函数指针转换为数据指针 */ cout << "reinterpret_cast***********************************************************" << endl; struct dat { short a; short b; }; long value = 0xA224B118; dat* pd = reinterpret_cast (&value); std::cout << std::hex << pd->a; // display first 2 bytes of value return 0; } Grand* GetOne() // generate one of three kinds of objects randomly { Grand* p = 0; switch (std::rand() % 3) { case 0: p = new Grand(std::rand() % 100); break; case 1: p = new Superb(std::rand() % 100); break; case 2: p = new Magnificent(std::rand() % 100, 'A' + std::rand() % 26); break; } return p; } void change(const int* pt, int n) { int* pc; pc = const_cast (pt); *pc += n; }
运行结果:
dynamic_cast*************************************************************** I am a grand class! I am a magnificent class!!! I hold the character Q and the integer 0! I am a magnificent class!!! I hold the character X and the integer 42! I am a magnificent class!!! I hold the character D and the integer 56! I am a superb class!! I hold the superb value of 29! typeid*************************************************************** Now processing type class Magnificent. I am a magnificent class!!! I hold the character H and the integer 5! Yes, you're really magnificent. Now processing type class Grand. I am a grand class! Now processing type class Grand. I am a grand class! Now processing type class Grand. I am a grand class! Now processing type class Superb. I am a superb class!! I hold the superb value of 92! const_cast*************************************************************** pop1, pop2: 38383, 2000 pop1, pop2: 38280, 2000 static_cast*************************************************************** I am a grand class! I am a superb class!! var = 99 var1 = 99.000000 reinterpret_cast*********************************************************** b118 D:\Prj\_C++Self\_1已统计代码\_18Runtime_Type_Identification\Debug\_18Runtime_Type_Identification.exe (进程 3700)已退出,代码为 0。 要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。 按任意键关闭此窗口. . .