| RTTI | Run-Time Type Information | 运行时类型信息 |
| Run-Time Type Identification | 运行时类型识别 |
C++ 通过下面两个操作符提供RTTI功能
-
typeid
-
dynamic_cast
其中:
-
typeid 返回type_info类的对象的一个引用
-
typeid 会抛出bad_typeid的异常
-
dynamic_cast 会抛出bad_cast异常
这3个类在头文件 typeinfo 中:
namespace std{
class type_info;
class bad_cast;
class bad_typeid;
}
typeid 操作符
- 操作符 typeid 用法上类似于操作符 sizeof (?)
-
只有当 typeid 的参数是带虚函数的类类型的对象的时候,才返回动态类型信息.
- 对其他,返回静态的、编译时的类型
例子:
#include <typeinfo>
#include <iostream>
#include <string>
#include <vector>
using std::cout;
using std::endl;
int func(int arg){return 0;}
typedef int (*func_ptr)(int arg);
class Base {public: Base(){}};
int main()
{
int integer(1);
double real(1.0);
int array[10]={1,2,3};
int * array_header = array;
std::string string;
std::vector<int> int_vector;
func_ptr f = func;
cout<<"integer : "<<typeid(integer).name() <<endl;
cout<<"real : "<<typeid(real).name() <<endl;
cout<<"array[10] : "<<typeid(array).name() <<endl;
cout<<"array_header: "<<typeid(array_header).name()<<endl;
cout<<"std::string : "<<typeid(string).name() <<endl;
cout<<"std::vector : "<<typeid(int_vector).name() <<endl;
cout<<"function : "<<typeid(func).name() <<endl;
cout<<"function ptr: "<<typeid(f).name() <<endl;
cout<<"custom class: "<<typeid(Base()).name() <<endl;
cout<<std::endl;
cout<<"int : "<<typeid(int).name() <<endl;
cout<<"double : "<<typeid(double).name() <<endl;
cout<<"std::vector : "<<typeid(std::vector<int>).name()<<endl;
cout<<"Base : "<<typeid(Base).name() <<endl;
cout<<"Base* : "<<typeid(Base*).name() <<endl;
cout<<"Base& : "<<typeid(Base&).name() <<endl;
return 0;
}
结果:
| g++ | MSVC | |
| integer | i | int |
| real | d | double |
| array[10] | A10_i | int [10] |
| array_header | Pi | int * |
| std::string | Ss | classstd::basic_string<char,structstd::char_traits<char> |
| std::vector | St6vectorIiSaIiEE | classstd::vector<int,classstd::allocator<int>> |
| function | FiiE | int__cdecl(int) |
| function ptr | PFiiE | int(__cdecl*)(int) |
| custom class | F4BasevE | classBase__cdecl(void) |
| int | i | int |
| double | d | double |
| std::vector | St6vectorIiSaIiEE | classstd::vector<int,classstd::allocator<int>> |
| Base | 4Base | class Base |
| Base* | P4Base | class Base * |
| Base& | 4Base | class Base |
对于每个类型,返回一个唯一的字符串,但该字符串的具体内容,与编译器实现有关。
在 typeid 中:
- 数组不会退化为指针,比如int array[10]
- 函数不会退化为指针, func 和 f
- 顶层cv-qualifiers会被忽略 typeid(D) == typeid(const D);
- ...
dynamic_cast 操作符
#include <typeinfo>
#include <iostream>
class Base1 { public: virtual void func1(){} };
class Base2 { public: virtual void func2(){} };
class D:public Base1, public Base2 {};
int main()
{
Base1 * b1 = new D;
Base2 & b2 = dynamic_cast<Base2&>(*b1);
std::cout << "Base1 " << uintptr_t(b1) <<" " << typeid(*b1).name() << std::endl
<< "Base2 " << uintptr_t(&b2) << " " <<typeid(b2).name() << std::endl;
return 0;
}
结果:
| MSVC | g++ |
| Base1 208960 class D | Base1 208088 1D |
C++0x 5.2.7:
-
The result of the expression dynamic_cast<T>(v) is the result of converting the expression v to type T. T shall be a pointer or reference to a complete class type, or “pointer to cv void.”
在dynamic_cast<T>(v)中,T 是一个完整定义类的指针或引用,或者void*。只能转换到void*,不能从void*转换回来。
type_info 类
摘自 C++0x标准 18.7.1:
namespace std {
class type_info {
public:
virtual ~type_info();
bool operator==(const type_info& rhs) const;
bool operator!=(const type_info& rhs) const;
bool before(const type_info& rhs) const;
size_t hash_code() const throw();
const char* name() const;
type_info(const type_info& rhs) = delete; // cannot be copied
type_info& operator=(const type_info& rhs) = delete; // cannot be copied
};
}
这里面,我们目前最感兴趣的是成员函数: name()
bad_typeid 类
异常的定义(来自C++0x 18.7.3):
namespace std {
class bad_typeid : public exception {
public:
bad_typeid() throw();
bad_typeid(const bad_typeid&) throw();
bad_typeid& operator=(const bad_typeid&) throw();
virtual const char* what() const throw();
};
}
例子:
#include <iostream>
#include <typeinfo>
class Polymorphic {virtual void Member(){}};
int main ()
{
try {
Polymorphic * pb = 0;
std::cout << typeid(*pb).name();
} catch (std::bad_typeid& e) {
std::cerr << "bad_typeid caught: " << e.what() << std::endl;
}
return 0;
}
结果:
| MSVC | bad_typeid caught: Attempted a typeid of NULL pointer! |
| g++ | bad_typeid caught: std::bad_typeid |
异常产生条件:
- 多态
- 空指针
- 用*解引用
比如,如果pb定义改为
int * pb = 0;
或 typeid 行改为
std::cout << typeid(pb).name();
则不会有异常发生。
bad_cast 类
异常的定义(来自C++0x 18.7.2):
namespace std {
class bad_cast : public exception {
public:
bad_cast() throw();
bad_cast(const bad_cast&) throw();
bad_cast& operator=(const bad_cast&) throw();
virtual const char* what() const throw();
};
}
例子:
#include <iostream>
#include <typeinfo>
class Base {virtual void Member(){}};
class Derived : Base {};
int main ()
{
try {
Base b;
Derived& rd = dynamic_cast<Derived&>(b);
} catch (std::bad_cast& bc) {
std::cerr << "bad_cast caught: " << bc.what() << std::endl;
}
return 0;
}
结果:
| MSVC | bad_cast caught: Bad dynamic_cast! |
| g++ | bad_cast caught: std::bad_cast |
- 对指针cast失败,返回一个空指针
- 对引用cast失败,则抛出bad_cast异常
本文详细介绍了C++中的运行时类型信息(RTTI)功能,包括typeid操作符和dynamic_cast操作符的使用方法及注意事项。并通过示例展示了如何获取类型信息和进行安全的类型转换。
281

被折叠的 条评论
为什么被折叠?



