Table of Contents

1.dynamic_cast工作原理

2.dynamic_cast介绍

3.static_cast与dynamic_cast

4.typeid


1.dynamic_cast工作原理

《深度探索C++对象模型》中有个例子:

class Point
{
public:Point(float xval);virtual ~Point();float x() const;static int PointCount();protected:virtual ostream& print(ostream& os) const;float _x;static int _point_count;
};

这个类的内存布局:

type_info是C++ Standard所定义的类型描述器,type_info中放置着每个类的类型信息。virtual table的第一个slot存有type_info的地址。

《The C++ Programming Language》中有个例子:

class My_slider: public Ival_slider { // polymor phic base (Ival_slider has virtual functions)
// ...
};

void g(Ival_box* pb, Date* pd)
{My_slider* pd1 = dynamic_cast<My_slider*>(pb); // OK
}

那么上述dynamic_cast的一个典型实现是:

My_slider的type_info会被编译器产生出来。pb指向的对象的type_info会在运行时通过vptr取得。这两个type_info会被交给runtime library函数,比较之后告诉我们是否吻合。如果吻合,返回转换后的My_slider*;否则返回nullptr。

2.dynamic_cast介绍

在运行时使用类型信息就叫做“run-time type identification”, 即RTTI。

downcast:从基类向子类转换;

upcast:从子类向基类转换;

crosscast:多重继承下,从一个基类到兄弟类的转换.如BBwindow到lval_box转换。

对dynamic_cast来说,upcast就像赋值操作一样,并没有多少耗费资源。dynamic_cast是用来解决编译时无法知道转换是否正确的场景。dynamic_cast要求操作对象是指向一个多态类型(含有虚函数)的指针或引用,来进行downcast或crosscast。

class My_slider: public Ival_slider { // polymor phic base (Ival_slider has virtual functions)
// ...
};class My_date : public Date { // base not polymorphic (Date has no virtual functions)
// ...
};void g(Ival_box* pb, Date* pd)
{My_slider* pd1 = dynamic_cast<My_slider*>(pb); // OKMy_date* pd2 = dynamic_cast<My_date*>(pd); // error : Date not polymorphic
}

多重继承:

class Component
: public virtual Storable { /* ... */ };
class Receiver
: public Component { /* ... */ };
class Transmitter
: public Component { /* ... */ };
class Radio
: public Receiver, public Transmitter { /* ... */ };

这里,一个Radio对象有两个Component基类对象。因此,在一个Radio对象内部从Storable到Component的dynamic_cast是模糊的,将会返回0.

void h1(Radio& r)
{Storable* ps = &r; // a Radio has a unique Storable// ...Component* pc = dynamic_cast<Component*>(ps); // pc = 0; a Radio has two Components// ...
}

3.static_cast与dynamic_cast

dynamic_cast可以将一个多态虚基类转换成子类或邻近兄弟类。但是static_cast不能,因为它不会对它的操作对象进行检查类型。

void g(Radio& r)
{Receiver* prec = &r; // Receiver is an ordinary base of RadioRadio* pr = static_cast<Radio*>(prec); // OK, uncheckedpr = dynamic_cast<Radio*>(prec); // OK, run-time checkedStorable* ps = &r; // Storable is a virtual base of Radiopr = static_cast<Radio*>(ps); //error : cannot cast from virtual basepr = dynamic_cast<Radio*>(ps); // OK, run-time checked
}

编译器无法预知被void*指针指向的内存的信息。因此,对于需要查看对象类型的dynamic_cast而言,它无法对void*进行转换。而static_cast在这种情况下可以做到。

Radio* f1(void* p)
{Storable* ps = static_cast<Storable*>(p); // trust the programmerreturn dynamic_cast<Radio*>(ps);
}

dynamic_cast和static_cast都无法对const指针或私有继承的指针进行转换。static_cast或者reinterpret_cast都无法将操作对象转换成私有基类。

class Users : private set<Person> { /* ... */ };
void f2(Users* pu, const Receiver* pcr)
{static_cast<set<Person>*>(pu); // error : access violationdynamic_cast<set<Person>*>(pu); // error : access violationstatic_cast<Receiver*>(pcr); //error : can’t cast away constdynamic_cast<Receiver*>(pcr); //error : can’t cast away constReceiver* pr = const_cast<Receiver*>(pcr); // OK// ...
}

4.typeid

typeid()返回指针或引用指向的对象的类型信息type_info。如果typeid()的操作数是nullptr,那么typeid()会抛出std::bad_typeid的异常。

void f(Shape& r, Shape* p)
{typeid(r); // type of the object referred to by rtypeid(*p); // type of the object pointed to by ptypeid(p); // type of the pointer, that is, Shape* (uncommon, except as a mistake)
}

type_info定义:

class type_info {// data
public:virtual ˜type_info(); //is polymorphicbool operator==(const type_info&) const noexcept; // can be comparedbool operator!=(const type_info&) const noexcept;bool before(const type_info&) const noexcept; // orderingsize_t hash_code() const noexcept; // for use by unordered_map and the likeconst char* name() const noexcept; // name of typetype_info(const type_info&) = delete; // prevent copyingtype_info& operator=(const type_info&) = delete; // prevent copying
};

例子:

struct Poly { // polymor phic base classvirtual void f();// ...
};
struct Non_poly { /* ... */ }; // no virtual functions
struct D1 : Poly { /* ... */ };
struct D2 : Non_poly { /* ... */ };void f(Non_poly& npr, Poly& pr)
{cout << typeid(npr).name() << '\n'; // writes something like "Non_poly"cout << typeid(pr).name() << '\n'; // name of Poly or a class derived from Poly
}
void g()
{D1 d1;D2 d2;f(d2,d1); // writes "Non_poly D1"
}

参考资料:

1.《深度探索C++对象模型》

2.《The C++ Programming Language》

[C++] - dynamic_cast介绍及工作原理、typeid、type_info相关推荐

  1. 三极管的介绍及工作原理

    转载自[http://www.elecfans.com/yuanqijian/sanjiguang/20170425510870.html] 三极管的介绍及工作原理 三极管介绍 三极管的工作原理 一. ...

  2. RabbitMQ介绍及工作原理

    RabbitMQ介绍及工作原理 一,什么是RabbitMQ ​ RabbitMQ是一种称为消息代理或队列管理器的消息队列软件.它是一个可以定义队列的软件,应用程序可以连接到队列并将消息传输到它们.消息 ...

  3. ETL介绍及工作原理

    ETL介绍及工作原理 ETL简介 ETL如何工作? 数据集的定义 ETL简介 ETL即EXTRACT(提取).Transform(转换).LOAD(加载): 提取是从数据库读取数据的过程.在此阶段,通 ...

  4. Heartbeat的介绍及工作原理

    一.HeartBeat的概述 Heartbeat 项目是 Linux-HA 工程的一个组成部分,自1999年开始到现在,发布了众多版本,是目前开源Linux-HA项目最成功的一个例子,它实现了一个高可 ...

  5. CPU构成详细介绍以及工作原理

    中央处理器(CPU,Central Processing Unit)是一块超大规模的集成电路,是一台计算机的运算核心(Core)和控制核心( Control Unit).它的功能主要是解释计算机指令以 ...

  6. Fidder介绍、工作原理

    https://www.cnblogs.com/R-bear/p/7508133.html 一:Fidder介绍 Fidder是web端比较易用的调试工具:它能够记录所有客户端.服务端的http.ht ...

  7. JAVA知识积累 JSP第一篇【JSP介绍、工作原理、生命周期、语法、指令、行为】...

    什么是JSP JSP全名为Java Server Pages,java服务器页面.JSP是一种基于文本的程序,其特点就是HTML和Java代码共同存在! 为什么需要JSP JSP是为了简化Servle ...

  8. ocsng mysql connection problem_OCSNG 介绍及其工作原理

    OCSNG部署:http://wowking.blog.51cto.com/1638252/994441 OCSNG 是什么呢? OCSNG就是Open Computer and Software I ...

  9. Docker Weave 介绍 or 工作原理

    Docker Weave Network Weave Network:属于第三方网络项目. Weave在Docker主机之间实现Overlay网络,使用业界标准VXLAN封装,基于UDP传输,也可以加 ...

最新文章

  1. 对于索引(a,b,c),下列哪些说法是正确的
  2. jenkins邮件通知功能
  3. YII1 MVC初认识(二)
  4. vue cli vue 3.x
  5. robotframework--登录接口,post传递多个参数、及获取content中指定属性的值(5)
  6. 2021年游戏项目的十大编程语言:C++、Java、C#均上榜
  7. Unity入门之路0-Unity下载安装以及版本选择
  8. c++一本通在线测评网站 1161:转进制
  9. Drilldown饼状图
  10. Win10加Ubuntu20.04双系统安装教程
  11. 排列组合 C语言函数,排列组合(C递归版)
  12. Python - 怎么将一个数字拆分成多个随机数字
  13. open-falcon短信报警
  14. 墨刀怎么注册_常见的登陆注册原型模板,墨刀都为你准备好了(直接使用)
  15. 返回不大于log2N的最大整数
  16. 000001历史数据_平安银行(000001) - 历史数据 - 股票工具
  17. 全国超能吃辣的省份,连四川和湖南都不是对手
  18. git 详解-进阶篇
  19. (转)神奇的数据挖掘
  20. A1490. osu!(乔明达)

热门文章

  1. linux下java基于UDP编程聊天_基于Linux下的UDP编程
  2. geth运行报错zsh: exec format error: ./geth
  3. html video各种控制命令,HTML5 Video(视频)
  4. antd 下拉框怎么联动_Antd的Table组件嵌套Table以及选择框联动操作
  5. Java抓取Codeforces——针对某一次提交的源码和数据
  6. android崩溃拦截给出提示显示日志
  7. 字符串匹配之KMP算法
  8. Hough transform(霍夫变换)
  9. java_eclipse_maven_svn_主题彩色插件_全屏插件
  10. How to Install apk to Android Devices from Mac OS X