typeid 与 dynamic_cast(C++学习)

2023-11-03

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异常

参考



FROM: http://blog.csdn.net/dbzhang800/article/details/6672591


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

typeid 与 dynamic_cast(C++学习) 的相关文章

  • Java 计算机网络相关基础知识

    实现通信的条件 IP Internet Protocol IP地址 IP地址具有唯一性 IP地址范围 0 0 0 0 255 255 255 255 本地IP地址 127 0 0 1 或 0 0 0 0 TCP Transmission C
  • related work 怎么写

    Related work精神 related work不需要写得特别细节 特别精确 但是要写出 意思 恕我驽钝 还是木有领会到 意思 是啥意思 感觉好像中国山水画一样 Related work整体写作思路 一般是将当前工作分成几大类 每个大
  • B - Marbles Gym - 101908B SG函数

    有一堆棋子在棋盘上 A和B轮流走 每次可以取一个棋子向上或向左走任意步 或者向上以及向右走x步 最先把一个棋子移动到0 0的人赢 问A能不能赢 SG 保证当前状态的子状态的sg都已经求出 把子状态的sg放入集合 第一个不在集合中的数就是当前
  • UNIX 环境编程 之 fork 函数详解

    一 概述 一个进程 包括代码 数据和分配给进程的资源 fork 函数通过系统调用创建一个与原来进程几乎完全相同的进程 也就是两个进程可以做完全相同的事 但如果初始参数或者传入的变量不同 两个进程也可以做不同的事 二 fork 函数 fork
  • JavaEE--------SpringMVC框架

    目录 1 SpringMVC简介 1 1 什么是MVC 1 2 什么是SpringMVC 1 3 SpringMVC的特点 2 入门案例 2 1 开发环境 2 2 创建maven工程 2 3 配置web xml 2 4 创建请求控制器 Co
  • 在linux系统下做软raid教程

    raid制作方法分为两种 一种为使用raid卡或者sas卡做的raid 我们称之为硬raid 一种则是在linux系统下做raid 我们称之为软raid 下面简单写下怎么在系统下做软raid 以raid0为例 如图所示 lsblk 查看现有
  • postman汉化设置

    1 下载 postman 汉化包 https github com hlmd Postman cn releases 挑选最新版本 一般汉化包更新比 postman 慢 所以我们选最新的就好 记住汉化包的版本 2 根据 汉化包 下载 相应的

随机推荐