关键字:static_cast,dynamic_cast,fast_dynamic_cast,VS 2015。

OS:Window 10。

C++类之间类型转换有:static_cast、dynamic_cast、reinterpret_cast、和const_cast。

static_cast - 编译时类型检查。如果没有继承关系的类之间转换编译不通过。优点是快,缺点是从父类转换到子类不安全的。

dynamic_cast - 运行时类型检查。可以父子之间转换,也可以兄弟之间转换。优点是安全,缺点是运行时效率低。

reinterpret_cast - 强制转换。最不安全。只有特定场合才能使用。

const_cast - const类型和非const类型互转。

一般从父类转换到子类,或兄弟类之间转换使用dynamic_cast是正确的选择。但是对于大型应用程序的底层开发,dynamic_cast的性能问题就暴露出来了,使用static_cast又不能保证安全,这时就需要自己实现一套高效安全的运行时动态类型转换。

基于虚函数+类型检查的类型转换

1. 为每个类实现classType和queryObject方法。运行时,通过虚函数queryObject调用以及在queryObject里面检查classType来找到合适的对象。具体实现如下:

    class A
{
public:
static const char* classType();
virtual void* queryObject(const char* classType) const;
}; const char* A::classType()
{
static const char* s_classType = "A";
return s_classType;
} void* A::queryObject(const char* classType) const
{
if (classType == A::classType())
return const_cast<A*>(this); return nullptr;
} class B
{
public:
static const char* classType();
virtual void* queryObject(const char* classType) const;
}; const char* B::classType()
{
static const char* s_classType = "B";
return s_classType;
} void* B::queryObject(const char* classType) const
{
if (classType == B::classType())
return const_cast<B*>(this); return nullptr;
} class C : public A, public B
{
public:
static const char* classType();
void* queryObject(const char* classType) const override;
}; const char* C::classType()
{
static const char* s_classType = "C";
return s_classType;
} void* C::queryObject(const char* classType) const
{
if (classType == C::classType())
return const_cast<C*>(this); if (void* res = A::queryObject(classType))
return res; if (void* res = B::queryObject(classType))
return res; return nullptr;
} class D : public A
{
public:
static const char* classType();
void* queryObject(const char* classType) const override;
}; const char* D::classType()
{
static const char* s_classType = "D";
return s_classType;
} void* D::queryObject(const char* classType) const
{
if (classType == D::classType())
return const_cast<D*>(this); return A::queryObject(classType);
} template <typename To, typename From>
To* fast_dynamic_cast(const From* from)
{
if (!from)
return nullptr; return static_cast<To*>(from->queryObject(To::classType()));
}

2. new对象C,用指针A指向C对象。C继承于A和B。

    A* a = new C();
cout << "A* a = new C();" << endl;

3. 测试类型转换从A到C,计时和检验转换结果。从测试结果看,dyanmic_cast、static_cast、fast_dynamic_cast结果都正确,static_cast效率最高,fast_dynamic_cast其次,dyanmic_cast效率最差。

    cout << "===== cast from pointer A to pointer C, should be not null =====" << endl;

    C* c = nullptr;
start = clock();
for (int i = ; i < count; i++)
{
c = dynamic_cast<C*>(a);
}
stop = clock();
cout << "dynamic_cast from A to C: " << c << ", " << "Time: " << stop - start << endl; c = nullptr;
start = clock();
for (int i = ; i < count; i++)
{
c = static_cast<C*>(a);
}
stop = clock();
cout << "static_cast from A to C: " << c << ", " << "Time: " << stop - start << endl; c = nullptr;
start = clock();
for (int i = ; i < count; i++)
{
c = fast_dynamic_cast<C>(a);
}
stop = clock();
cout << "fast_dynamic_cast from A to C: " << c << ", " << "Time: " << stop - start << endl;

测试结果:

===== cast from pointer A to pointer C, should be not null =====
dynamic_cast from A to C: 00000202D48C9FE0, Time:
static_cast from A to C: 00000202D48C9FE0, Time:
fast_dynamic_cast from A to C: 00000202D48C9FE0, Time:

4.  测试类型转换从A到B,计时和检验转换结果。从测试结果看,static_cast编译不通过,dyanmic_cast、fast_dynamic_cast结果都正确,fast_dynamic_cast效率比dyanmic_cast高。

    cout << "\n===== cast from pointer A to pointer B, should be not null =====" << endl;

    B* b = nullptr;
start = clock();
for (int i = ; i < count; i++)
{
b = dynamic_cast<B*>(a);
}
stop = clock();
cout << "dynamic_cast from A to B: " << b << ", " << "Time: " << stop - start << endl; b = nullptr;
start = clock();
for (int i = ; i < count; i++)
{
//b = static_cast<B*>(a); //compiler error
}
stop = clock();
cout << "static_cast from A to B: " << "compiler error" << endl; b = nullptr;
start = clock();
for (int i = ; i < count; i++)
{
b = fast_dynamic_cast<B>(a);
}
stop = clock();
cout << "fast_dynamic_cast from A to B: " << b << ", " << "Time: " << stop - start << endl;

测试结果:

===== cast from pointer A to pointer B, should be not null =====
dynamic_cast from A to B: 000001D65F2FA308, Time:
static_cast from A to B: compiler error
fast_dynamic_cast from A to B: 000001D65F2FA308, Time:

5. 测试类型转换从A到D,计时和检验转换结果。从测试结果看,static_cast结果不正确,应为空指针,dyanmic_cast、fast_dynamic_cast结果都正确,fast_dynamic_cast效率比dyanmic_cast高。

    cout << "\n===== cast from pointer A to pointer D, should be null =====" << endl;

    D* d = nullptr;
start = clock();
for (int i = ; i < count; i++)
{
d = dynamic_cast<D*>(a);
}
stop = clock();
cout << "dynamic_cast from A to D: " << d << ", " << "Time: " << stop - start << endl; d = nullptr;
start = clock();
for (int i = ; i < count; i++)
{
d = static_cast<D*>(a);
}
stop = clock();
cout << "static_cast from A to D: " << d << ", " << "Time: " << stop - start << endl; d = nullptr;
start = clock();
for (int i = ; i < count; i++)
{
d = fast_dynamic_cast<D>(a);
}
stop = clock();
cout << "fast_dynamic_cast from A to D: " << d << ", " << "Time: " << stop - start << endl;

测试结果:

===== cast from pointer A to pointer D, should be null =====
dynamic_cast from A to D: , Time:
static_cast from A to D: 0000026050C6D310, Time:
fast_dynamic_cast from A to D: , Time:

总结:根据以上测试结果,fast_dynamic_cast和dynamic_cast行为完全一致,并且效率上fast_dynamic_cast比dynamic_cast快10倍以上,在追求性能的底层开发完全可以用fast_dynamic_cast代替dynamic_cast。

附完整代码:

#include "stdafx.h"

#include <string>
#include <time.h>
#include <iostream> using namespace std; namespace
{
class A
{
public:
static const char* classType();
virtual void* queryObject(const char* classType) const;
template <typename From>
static A* queryObject(const From* from)
{
if (!from)
return nullptr; return static_cast<A*>(from->queryObject(A::classType()));
}
}; const char* A::classType()
{
static const char* s_classType = "A";
return s_classType;
} void* A::queryObject(const char* classType) const
{
if (classType == A::classType())
return const_cast<A*>(this); return nullptr;
} class B
{
public:
static const char* classType();
virtual void* queryObject(const char* classType) const;
template <typename From>
static B* queryObject(const From* from)
{
if (!from)
return nullptr; return static_cast<B*>(from->queryObject(B::classType()));
}
}; const char* B::classType()
{
static const char* s_classType = "B";
return s_classType;
} void* B::queryObject(const char* classType) const
{
if (classType == B::classType())
return const_cast<B*>(this); return nullptr;
} class C : public A, public B
{
public:
static const char* classType();
void* queryObject(const char* classType) const override;
template <typename From>
static C* queryObject(const From* from)
{
if (!from)
return nullptr; return static_cast<C*>(from->queryObject(C::classType()));
}
}; const char* C::classType()
{
static const char* s_classType = "C";
return s_classType;
} void* C::queryObject(const char* classType) const
{
if (classType == C::classType())
return const_cast<C*>(this); if (void* res = A::queryObject(classType))
return res; if (void* res = B::queryObject(classType))
return res; return nullptr;
} class D : public A
{
public:
static const char* classType();
void* queryObject(const char* classType) const override;
template <typename From>
static D* queryObject(const From* from)
{
if (!from)
return nullptr; return static_cast<D*>(from->queryObject(D::classType()));
}
}; const char* D::classType()
{
static const char* s_classType = "D";
return s_classType;
} void* D::queryObject(const char* classType) const
{
if (classType == D::classType())
return const_cast<D*>(this); return A::queryObject(classType);
} template <typename To, typename From>
To* fast_dynamic_cast(const From* from)
{
return To::queryObject(from);
}
} int main()
{
A* a = new C();
cout << "A* a = new C();" << endl; clock_t start, stop;
const int count = ; cout << "===== cast from pointer A to pointer C, should be not null =====" << endl; C* c = nullptr;
start = clock();
for (int i = ; i < count; i++)
{
c = dynamic_cast<C*>(a);
}
stop = clock();
cout << "dynamic_cast from A to C: " << c << ", " << "Time: " << stop - start << endl; c = nullptr;
start = clock();
for (int i = ; i < count; i++)
{
c = static_cast<C*>(a);
}
stop = clock();
cout << "static_cast from A to C: " << c << ", " << "Time: " << stop - start << endl; c = nullptr;
start = clock();
for (int i = ; i < count; i++)
{
c = fast_dynamic_cast<C>(a);
}
stop = clock();
cout << "fast_dynamic_cast from A to C: " << c << ", " << "Time: " << stop - start << endl; cout << "\n===== cast from pointer A to pointer B, should be not null =====" << endl; B* b = nullptr;
start = clock();
for (int i = ; i < count; i++)
{
b = dynamic_cast<B*>(a);
}
stop = clock();
cout << "dynamic_cast from A to B: " << b << ", " << "Time: " << stop - start << endl; b = nullptr;
start = clock();
for (int i = ; i < count; i++)
{
//b = static_cast<B*>(a); //compiler error
}
stop = clock();
cout << "static_cast from A to B: " << "compiler error" << endl; b = nullptr;
start = clock();
for (int i = ; i < count; i++)
{
b = fast_dynamic_cast<B>(a);
}
stop = clock();
cout << "fast_dynamic_cast from A to B: " << b << ", " << "Time: " << stop - start << endl; cout << "\n===== cast from pointer A to pointer D, should be null =====" << endl; D* d = nullptr;
start = clock();
for (int i = ; i < count; i++)
{
d = dynamic_cast<D*>(a);
}
stop = clock();
cout << "dynamic_cast from A to D: " << d << ", " << "Time: " << stop - start << endl; d = nullptr;
start = clock();
for (int i = ; i < count; i++)
{
d = static_cast<D*>(a);
}
stop = clock();
cout << "static_cast from A to D: " << d << ", " << "Time: " << stop - start << endl; d = nullptr;
start = clock();
for (int i = ; i < count; i++)
{
d = fast_dynamic_cast<D>(a);
}
stop = clock();
cout << "fast_dynamic_cast from A to D: " << d << ", " << "Time: " << stop - start << endl; delete a;
a = nullptr;
return ;
}

C++高效安全的运行时动态类型转换的更多相关文章

  1. C# 在运行时动态创建类型

    C# 在运行时动态的创建类型,这里是通过动态生成C#源代码,然后通过编译器编译成程序集的方式实现动态创建类型 public static Assembly NewAssembly() { //创建编译 ...

  2. LINQ to SQL 运行时动态构建查询条件

    在进行数据查询时,经常碰到需要动态构建查询条件.使用LINQ实现这个需求可能会比以前拼接SQL语句更麻烦一些.本文介绍了3种运行时动态构建查询条件的方法.本文中的例子最终实现的都是同一个功能,从Nor ...

  3. 使用javassist运行时动态重新加载java类及其他替换选择

    在不少的情况下,我们需要对生产中的系统进行问题排查,但是又不能重启应用,java应用不同于数据库的存储过程,至少到目前为止,还不能原生的支持随时进行编译替换,从这种角度来说,数据库比java的动态性要 ...

  4. 运行时动态库:not found 及介绍-linux的-Wl,-rpath命令

    ---此文章同步自我的CSDN博客--- 一.运行时动态库:not found   今天在使用linux编写c/c++程序时,需要用到第三方的动态库文件.刚开始编译完后,运行提示找不到动态库文件.我就 ...

  5. 转: gcc 指定运行时动态库路径

    gcc 指定运行时动态库路径 Leave a reply 由于种种原因,Linux 下写 c 代码时要用到一些外部库(不属于标准C的库),可是由于没有权限,无法将这写库安装到系统目录,只好安装用户目录 ...

  6. [转] Java运行时动态生成class的方法

    [From] http://www.liaoxuefeng.com/article/0014617596492474eea2227bf04477e83e6d094683e0536000 廖雪峰 / 编 ...

  7. 运行时动态伪造vsprintf的va_list

    运行时动态伪造vsprintf的va_list #include <stdio.h> int main() { char* m = (char*) malloc(sizeof(int)*2 ...

  8. SpringBoot运行时动态添加数据源

    此方案适用于解决springboot项目运行时动态添加数据源,非静态切换多数据源!!! 一.多数据源应用场景: 1.配置文件配置多数据源,如默认数据源:master,数据源1:salve1...,运行 ...

  9. 解决 Retrofit 多 BaseUrl 及运行时动态改变 BaseUrl ?

    原文地址: juejin.im/post/597856- 解决Retrofit多BaseUrl及运行时动态改变BaseUrl(一) 解决Retrofit多BaseUrl及运行时动态改变BaseUrl( ...

随机推荐

  1. (luogu4180) [Beijing2010组队]次小生成树Tree

    严格次小生成树 首先看看如果不严格我们怎么办. 非严格次小生成树怎么做 由此,我们发现一个结论,求非严格次小生成树,只需要先用kruskal算法求得最小生成树,然后暴力枚举非树边,替换路径最大边即可. ...

  2. 【BZOJ2527】MET-Meteors(整体二分)

    [BZOJ2527]MET-Meteors(整体二分) 题面 BZOJ权限题,良心洛谷链接 题解 其实我也不会做 看了zsy博客才会做... 这题如果直接爆算做显然行不通 如果只有单次询问,我们就可以 ...

  3. 小程序wx.navigateTo和wx.redirectTo 都无效

    最近在写小程序,遇到页面跳转时,发现有几次失败.查询资料已解决,总结一下知识点: 一.如下,第5层到到6层时失败(评论页⑤-->返回商品详情页⑥) 登陆①-->主页②-->商品列表页 ...

  4. linux 添加ftp用户与登录配置详解

    不同类Unix有一定区别 版本不同也有些区别 在linux主机上如何添加ftp用户 (一)修改配置文件 vi /etc/vsftpd/vsftpd.conf 在96行,97,98行 96 chroot ...

  5. lambda表达式Expression<Func<Person, bool>> 、Func<Person, bool>区别

    前言: 自己通过lambda表达式的封装,将对应的表达式转成字符串的过程中,对lambda表达式有了新的认识 原因: 很多开发者对lambda表达式Expression<Func<Pers ...

  6. php 命令行插件 - phpsh

    phpsh 是php的一个命令行插件,个人觉得很不错,在此简单介绍下: 1.安装 readline sudo easy_install readline 2.到 https://github.com/ ...

  7. html5判断浏览器来源并跳转

    <script type="text/javascript"> var system ={}; var p = navigator.platform; system.w ...

  8. Silverlight的认识

    Microsoft Silverlight是一个跨浏览器的.跨平台的插件.Silverlight提供灵活的编程模型,并可以很方便地集成到现有的网络应用程序中.Silverlight可以对运行在Mac或 ...

  9. linux修改时区

    Linux修改时区 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任 CentOS6: 查看以前的时区: [root@localhost mysq ...

  10. 【前端】input radio多选事件获取所有选中的id,radio样式优化可修改

    $("#all_button").on('click', function() { obj = document.getElementsByClassName("inpu ...