c++ typeid关键字的使用

typeid关键字

注意:typeid是操作符,不是函数。这点与sizeof类似)

运行时获知变量类型名称,可以使用 typeid(变量).name()

需要注意不是所有编译器都输出”int”、”float”等之类的名称,对于这类的编译器可以这样使用

 int ia = 3;
 if(typeid(ia) == typeid(int))
 {
   cout <<"int" <<endl;
 }

RTTI(Run-Time Type Identification)-运行时类型识别

在揭开typeid神秘面纱之前,我们先来了解一下RTTI(Run-Time Type Identification,运行时类型识别),它使程序能够获取由基指针或引用所指向的对象的实际派生类型,即允许“用指向基类的指针或引用来操作对象”的程序能够获取到“这些指针或引用所指对象”的实际派生类型。

在C++中,为了支持RTTI提供了两个操作符:dynamic_cast和typeid

  • dynamic_cast允许运行时刻进行类型转换,从而使程序能够在一个类层次结构中安全地转化类型,与之相对应的还有一个非安全的转换操作符static_cast,因为这不是本文的讨论重点,所以这里不再详述,感兴趣的可以自行查阅资料。
  • typeid是C++的关键字之一,等同于sizeof这类的操作符。typeid操作符的返回结果是名为type_info的标准库类型的对象的引用(在头文件typeinfo中定义,稍后我们看一下vs和gcc库里面的源码),它的表达式有下图两种形式。

实现机制与使用技巧

type_info类对象类别判别

对象类别判别分析

如果表达式的类型是类类型且至少包含有一个虚函数,则typeid操作符返回表达式的动态类型,需要在运行时计算;
否则,typeid操作符返回表达式的静态类型,在编译时就可以计算。

ISO C++标准并没有确切定义type_info,它的确切定义编译器相关的,但是标准却规定了其实现必需提供如下四种操作(在之后的章节中我会来分析type_info类文件的源码)

运算 描述
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的字符串,用来表示相应的类型名,但务必注意这个返回的类型名与程序中使用的相应类型名并不一定一致(往往如此,见后面的程序),这具体由编译器的实现所决定的,标准只要求实现为每个类型返回唯一的字符串。

type_info类源代码

使用sudo find / -name typeinfo.h来查找源码

#ifndef _TYPEINFO
#define _TYPEINFO

#include <exception>

namespace std
{

 class type_info
 {
 public:

  virtual ~type_info();
  { return __name[0] == '*' ? __name + 1 : __name; }

  bool before(const type_info& __arg) const
  { return __name < __arg.__name; }

  bool operator==(const type_info& __arg) const
  { return __name == __arg.__name; }

  bool operator!=(const type_info& __arg) const
  { return !operator==(__arg); }

  virtual bool __is_pointer_p() const;

  virtual bool __is_function_p() const;

 protected:
  const char *__name;

  explicit type_info(const char *__n): __name(__n) { }

 private:
  type_info& operator=(const type_info&);
  type_info(const type_info&);
 };

} // extern "C++"
#endif

示例1-基本数据类型

下表列出了使用typeid操作符的表达式的值

 int a;
 double b;
 char * c;
 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类(用于描述数据类型的一个系统类)对象的引用。这个操作符可以用于表达式和类型名(包括自定的数据类型,比如类)。

示例2-类对象

class base
{
public :
  void m(){cout<<"base"<<endl;}
};
class derived : public base
{
public:
  void m(){cout<<"derived"<<endl;}
};

假设我们根据例2中定义的两个类来定义如下指针:

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)为真。

示例3-带虚函数的基类

class base
{
public :
  virtual void m(){cout<<"base"<<endl;}
};
class derived : public base
{
public:
  void m(){cout<<"derived"<<endl;}
};

假设我们如本例所示定义了两个类base类和derived类,基于这两个类定义,我们定义指针如下:

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)为假。

异常处理bad_typeid

class bad_typeid : public exception
 {
 public:
  bad_typeid () throw() { }

  // This declaration is not useless:
  // http://gcc.gnu.org/onlinedocs/gcc-3.0.2/gcc_6.html#SEC118
  virtual ~bad_typeid() throw();

  // See comment in eh_exception.cc.
  virtual const char* what() const throw();
 };
} // namespace std

以上就是c++ typeid关键字的使用的详细内容,更多关于c++ typeid关键字的资料请关注我们其它相关文章!

(0)

相关推荐

  • 详解C++编程中的sizeof运算符与typeid运算符

    sizeof 运算符 产生与 char 类型的大小有关的操作数大小. 语法 sizeof unary-expression sizeof ( type-name ) 备注 sizeof 运算符的结果为 size_t 类型,它是包含文件 STDDEF.H 中定义的整数类型.利用此运算符,你可以避免在程序中指定依赖于计算机的数据大小. sizeof 的操作数可以是下列项之一: 类型名称.若要将 sizeof 用于类型名称,则该名称必须用括号括起. 一个表达式.当用于表达式时,无论是否使用括号都可指定

  • C++运行时获取类型信息的type_info类与bad_typeid异常

    type_info 类 type_info 类描述编译器在程序中生成的类型信息.此类的对象可以有效存储指向类型的名称的指针. type_info 类还可存储适合比较两个类型是否相等或比较其排列顺序的编码值.类型的编码规则和排列顺序是未指定的,并且可能因程序而异. 必须包含 <typeinfo> 标头文件才能使用 type_info 类. type_info 类的接口是: class type_info { public: virtual ~type_info(); size_t hash_co

  • C++11关于auto关键字的使用示例

    一.概述 auto关键字在c++98中已经出现,在98中定义为具有自动存储器的局部变量, c++11中标准委员会重新定义了auto关键字,表示一个类型占位符,告诉编译器,auto声明变量的类型必须由编译器在编译时期推导 而得. 注意事项: 1.auto关键字类型推断发生在编译期,程序运行时不会造成效率降低 2.auto关键字定义时就需要初始化 3.auto仅仅是一个占位符,它并不是一个真正的类型, 因此sizeof(auto)是错误的 4.auto不能作为函数的参数 5.auto不能定义数组,如

  • c++使用正则表达式提取关键字的方法

    下面看下c++通过正则表达式提取关键字,代码如下所示: string text = "岳云鹏的对象叫铁锤"; regex pattern("(.*)的对象叫(.*)"); smatch results; if (regex_match(text, results, pattern)) { for (auto it = results.begin(); it != results.end(); ++it) cout << *it << endl

  • 详解c++中的 static 关键字及作用

    注:若没有特指是 静态成员时,默认都是普通成员: 1 类中的普通成员 类中的成员变量 和 成员函数 是分开存储的.其中, 1)每个对象都有独立的成员变量:成员变量可以存储在 栈空间.堆空间.全局数据区: 2)所有对象共享类的成员函数:成员函数 只能存储在 代码段: 2 类中的静态成员(static) 类中的静态成员 1.用 static关键字 修饰: 2.可以用 类名::成员名 访问 静态成员: 3.静态成员 属于 整个类: 4.静态成员 是所属类的成员,其它类不能访问: 5.静态成员的内存分配

  • C++中volatile关键字及常见的误解总结

    前言 近期看到C++标准中对volatile关键字的定义,发现和java的volatile关键字完全不一样,C++的volatile对并发编程基本没有帮助.网上也看到很多关于volatile的误解,于是决定写这篇文章详细解释一下volatile的作用到底是什么. 为什么用volatile? C/C++ 中的 volatile 关键字和 const 对应,用来修饰变量,通常用于建立语言级别的 memory barrier.这是 BS 在 "The C++ Programming Language&

  • C/C++ 中const关键字的用法小结

    C++中的const关键字的用法非常灵活,而使用const将大大改善程序的健壮性. Const作用 NO. 作用 说明 参考 1 可以定义const常量 const int Max = 100; 2 便于进行类型检查 const常量有数据类型,而宏常量没有数据类型.编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换时可能会产生意料不到的错误 void f(const int i) { ---} //对传入的参数进行类型检查,不匹配进行提示 3 可以保护被修

  • C++ override关键字使用详解

    C++ override从字面意思上,是覆盖的意思,实际上在C++中它是覆盖了一个方法并且对其重写,从而达到不同的作用.在我们C++编程过程中,最熟悉的就是对接口方法的实现,在接口中一般只是对方法进行了声明,而我们在实现时,就需要实现接口声明的所有方法.还有一个典型应用就是在继承中也可能会在子类覆盖父类的方法. 公有继承包含两部分:一是"接口"(interface),二是 "实现" (implementation). 例如Person类的几种成员函数的继承方式: c

  • C++ Virtual关键字的具体使用

    基础理解和demo 普通的继承 #include<iostream> class Parent { public: void print() { std::cout << "Parent" << std::endl; } }; class Child : Parent { public: void print() { std::cout << "Child" << std::endl; } }; int m

  • C++面试基础之static关键字详解

    前言 static是 c++ 的关键字,顾名思义是表示静态的含义.它在 c++ 中既可以修饰变量也可以修饰函数.那当我们使用 static 时,编译器究竟做了哪些事情呢? 早先面试中被问到 static 关键字,感觉既熟悉又陌生.熟悉是都知道如何去使用它,陌生又来自不知道它究竟对我们程序做了什么.今天就来好好复习下这个关键字,本文的重点也在第三部分. 先看一下示例代码: test1.cpp #include <iostream> extern int a_int; extern void fu

  • 一文读懂c++之static关键字

    一.静态变量 与C语言一样,可以使用static说明自动变量.根据定义的位置不同,分为静态全局变量和静态局部变量. 全局变量是指在所有花括号之外声明的变量,其作用域范围是全局可见的,即在整个项目文件内都有效.使用static修饰的全局变量是静态全局变量,其作用域有所限制,仅在定义该变量的源文件内有效,项目中的其他源文件中不能使用它. 块内定义的变量是局部变量,从定义之处开始到本块结束处为止是局部变量的作用域.使用static修饰的局部变量是静态局部变量,即定义在块中的静态变量.静态局部变量具有局

随机推荐