注意:typeid是操做符,不是函数。这点与sizeof相似)html
运行时获知变量类型名称,能够使用 typeid(变量).name()安全
须要注意不是全部编译器都输出”int”、”float”等之类的名称,对于这类的编译器能够这样使用less
1 int ia = 3; 2 if(typeid(ia) == typeid(int)) 3 { 4 cout <<"int" <<endl; 5 }
在揭开typeid神秘面纱以前,咱们先来了解一下RTTI(Run-Time Type Identification,运行时类型识别),它使程序可以获取由基指针或引用所指向的对象的实际派生类型,即容许“用指向基类的指针或引用来操做对象”的程序可以获取到“这些指针或引用所指对象”的实际派生类型。ide
在C++中,为了支持RTTI提供了两个操做符:dynamic_cast
和typeid
函数
dynamic_cast容许运行时刻进行类型转换,从而使程序可以在一个类层次结构中安全地转化类型,与之相对应的还有一个非安全的转换操做符static_cast,由于这不是本文的讨论重点,因此这里再也不详述,感兴趣的能够自行查阅资料。spa
typeid是C++的关键字之一,等同于sizeof这类的操做符。typeid操做符的返回结果是名为type_info的标准库类型的对象的引用(在头文件typeinfo中定义,稍后咱们看一下vs和gcc库里面的源码),它的表达式有下图两种形式。指针
若是表达式的类型是类类型且至少包含有一个虚函数,则typeid操做符返回表达式的动态类型,须要在运行时计算;
不然,typeid操做符返回表达式的静态类型,在编译时就能够计算。code
ISO C++标准并无确切定义type_info
,它的确切定义编译器相关的,可是标准却规定了其实现必需提供以下四种操做(在以后的章节中我会来分析type_info类文件的源码)htm
运算 | 描述 |
---|---|
t1 == t2 | 若是两个对象t1和t2类型相同,则返回true;不然返回false |
t1 != t2 | 若是两个对象t1和t2类型不一样,则返回true;不然返回false |
t.name() | 返回类型的C-style字符串,类型名字用系统相关的方法产生1 |
t1.before(t2) | 返回指出t1是否出如今t2以前的bool值 |
type_info类提供了public虚 析构函数,以使用户可以用其做为基类。它的默认构造函数和拷贝构造函数及赋值操做符都定义为private,因此不能定义或复制type_info类型的对象。程序中建立type_info对象的惟一方法是使用typeid操做符(因而可知,若是把typeid看做函数的话,其应该是type_info的 友元)。type_info的name成员函数返回C-style的字符串,用来表示相应的类型名,但务必注意这个返回的类型名与程序中使用的相应类型名并不必定一致(每每如此,见后面的程序),这具体由编译器的实现所决定的,标准只要求实现为每一个类型返回惟一的字符串。对象
使用sudo find / -name typeinfo.h
来查找源码
1 #ifndef _TYPEINFO 2 #define _TYPEINFO
3
4 #include <exception>
5
6 namespace std 7 { 8
9 class type_info 10 { 11 public: 12
13 virtual ~type_info(); 14 { return __name[0] == '*' ? __name + 1 : __name; } 15
16
17 bool before(const type_info& __arg) const
18 { return __name < __arg.__name; } 19
20 bool operator==(const type_info& __arg) const
21 { return __name == __arg.__name; } 22
23 bool operator!=(const type_info& __arg) const
24 { return !operator==(__arg); } 25
26 virtual bool __is_pointer_p() const; 27
28 virtual bool __is_function_p() const; 29
30 protected: 31 const char *__name; 32
33 explicit type_info(const char *__n): __name(__n) { } 34
35 private: 36 type_info& operator=(const type_info&); 37 type_info(const type_info&); 38 }; 39
40 } // extern "C++"
41 #endif
下表列出了使用typeid操做符的表达式的值
1 int a; 2 double b; 3 char * c; 4 long d;
运算 | 描述 |
---|---|
typeid(a) == typeid(int) | true |
typeid(a) == typeid(float) | false |
typeid(a) == typeid(int *) | false |
typeid(b) == typeid(double) | true |
typeid(b) == typeid(float) | false |
typeid(b) == typeid(long double) | false |
typeid(c) == typeid(char *) | true |
typeid(c) == typeid(char) | false |
typeid(c) == typeid(string) | false |
typeid(d) == typeid(long) | true |
typeid(d) == typeid(int) | false |
操做符typeid返回的是一个type_info类(用于描述数据类型的一个系统类)对象的引用。这个操做符能够用于表达式和类型名(包括自定的数据类型,好比类)。
1 class base
2 { 3 public : 4 void m(){cout<<"base"<<endl;} 5 }; 6 class derived : public base
7 { 8 public: 9 void m(){cout<<"derived"<<endl;} 10 };
假设咱们根据例2中定义的两个类来定义以下指针:
1 base * p = new derived;
下表将给出使用typeid操做符的结果。
运算 | 描述 |
---|---|
typeid(p) == typeid(base*) | true |
typeid(p) == typeid(derived*) | false |
typeid(*p) == typeid(base) | true |
typeid(*p) == typeid(derived) | false |
对于表达式typeid(p),一样,由于p是base*类型的指针,所以typeid(p) == typeid(base*)为真,而typeid(p) == typeid(derived*)为假。而对于表达式typeid(*p),因为此时的基类不具备多态性,于是*p将会采用编译期类型来计算,编译期*p是base对象,所以表达式typeid(*p) == typeid(derived)为假,typeid(*p) == typeid(base)为真。
1 class base
2 { 3 public : 4 virtual void m(){cout<<"base"<<endl;} 5 }; 6 class derived : public base
7 { 8 public: 9 void m(){cout<<"derived"<<endl;} 10 };
假设咱们如本例所示定义了两个类base类和derived类,基于这两个类定义,咱们定义指针以下:
1 base * p = new derived;
下表将给出使用typeid操做符的结果。
运算 | 描述 |
---|---|
typeid(p) == typeid(base*) | true |
typeid(p) == typeid(derived*) | false |
typeid(*p) == typeid(base) | false |
typeid(*p) == typeid(derived) | true |
对于表达式typeid(p),由于p是base*类型的指针,所以typeid(p) == typeid(base*)为真,而typeid(p) == typeid(derived*)为假。而对于表达式typeid(*p),由于base类具备多态性,于是在计算typeid(*p)时会根据运行时p所指向的实际类型去计算,而本例中p指向的是派生类对象,所以表达式typeid(*p) == typeid(derived)为真,typeid(*p) == typeid(base)为假。
1 class bad_typeid : public exception 2 { 3 public: 4 bad_typeid () throw() { } 5
6 // This declaration is not useless: 7 // http://gcc.gnu.org/onlinedocs/gcc-3.0.2/gcc_6.html#SEC118
8 virtual ~bad_typeid() throw(); 9
10 // See comment in eh_exception.cc.
11 virtual const char* what() const throw(); 12 }; 13 } // namespace std