typeid 与 dynamic_cast



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

class std::basic_string<char,struct std::char_traits<char>
,class s td::allocator<char> >

std::vector

St6vectorIiSaIiEE

class std::vector<int,class std::allocator<int> > 

function

FiiE

int __cdecl(int)

function ptr

PFiiE

int (__cdecl*)(int)

custom class

F4BasevE

class Base __cdecl(void)

   

int

i

int

double

d

double

std::vector

St6vectorIiSaIiEE

class std::vector<int,class std::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
Base2 208964 class D

Base1 208088 1D
Base2 208092 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++,typeinfo)