C++高效安全的运行时动态类型转换
关键字: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++高效安全的运行时动态类型转换的更多相关文章
- C# 在运行时动态创建类型
C# 在运行时动态的创建类型,这里是通过动态生成C#源代码,然后通过编译器编译成程序集的方式实现动态创建类型 public static Assembly NewAssembly() { //创建编译 ...
- LINQ to SQL 运行时动态构建查询条件
在进行数据查询时,经常碰到需要动态构建查询条件.使用LINQ实现这个需求可能会比以前拼接SQL语句更麻烦一些.本文介绍了3种运行时动态构建查询条件的方法.本文中的例子最终实现的都是同一个功能,从Nor ...
- 使用javassist运行时动态重新加载java类及其他替换选择
在不少的情况下,我们需要对生产中的系统进行问题排查,但是又不能重启应用,java应用不同于数据库的存储过程,至少到目前为止,还不能原生的支持随时进行编译替换,从这种角度来说,数据库比java的动态性要 ...
- 运行时动态库:not found 及介绍-linux的-Wl,-rpath命令
---此文章同步自我的CSDN博客--- 一.运行时动态库:not found 今天在使用linux编写c/c++程序时,需要用到第三方的动态库文件.刚开始编译完后,运行提示找不到动态库文件.我就 ...
- 转: gcc 指定运行时动态库路径
gcc 指定运行时动态库路径 Leave a reply 由于种种原因,Linux 下写 c 代码时要用到一些外部库(不属于标准C的库),可是由于没有权限,无法将这写库安装到系统目录,只好安装用户目录 ...
- [转] Java运行时动态生成class的方法
[From] http://www.liaoxuefeng.com/article/0014617596492474eea2227bf04477e83e6d094683e0536000 廖雪峰 / 编 ...
- 运行时动态伪造vsprintf的va_list
运行时动态伪造vsprintf的va_list #include <stdio.h> int main() { char* m = (char*) malloc(sizeof(int)*2 ...
- SpringBoot运行时动态添加数据源
此方案适用于解决springboot项目运行时动态添加数据源,非静态切换多数据源!!! 一.多数据源应用场景: 1.配置文件配置多数据源,如默认数据源:master,数据源1:salve1...,运行 ...
- 解决 Retrofit 多 BaseUrl 及运行时动态改变 BaseUrl ?
原文地址: juejin.im/post/597856- 解决Retrofit多BaseUrl及运行时动态改变BaseUrl(一) 解决Retrofit多BaseUrl及运行时动态改变BaseUrl( ...
随机推荐
- 洛谷P3402 【模板】可持久化并查集(可持久化线段树,线段树)
orz TPLY 巨佬,题解讲的挺好的. 这里重点梳理一下思路,做一个小小的补充吧. 写可持久化线段树,叶子节点维护每个位置的fa,利用每次只更新一个节点的特性,每次插入\(logN\)个节点,这一部 ...
- 300行Kotlin代码实现的区块链
使用Kotlin实现的区块链基本逻辑! 源码地址 GitHub仓库 启动方式 启动参数添加 -Dserver.port=8080,启动不同的端口,模拟不同的节点. 假设目前启动了8080和8081两个 ...
- ssr 服务端安装教程
1 ShadowsocksR 多用户版服务端安装教程(SS-Panel后端) 2 ShadowsocksR 单用户版服务端安装教程
- Python可视化库-Matplotlib使用总结
在做完数据分析后,有时候需要将分析结果一目了然地展示出来,此时便离不开Python可视化工具,Matplotlib是Python中的一个2D绘图工具,是另外一个绘图工具seaborn的基础包 先总结下 ...
- 微信小程序之实现页面缩放式侧滑效果
效果图: 实现原理:点击按钮,往需要动画的div中添加或移除拥有动画效果的class. 由于微信小程序中不能操作page这个根节点,所以,只有用一个div(view)来模仿page根节点. 1.结构 ...
- 戴尔R720xd服务器系统安装
型号:R720xd 开启服务器,Ctrl+R进入raid配置 配置完raid后F2对硬盘进行格式化 保存并重启 F11进入BIOS选项设置U盘启动 选择U盘启动 开始进行系统安装!
- 原生js+canvas实现滑动拼图验证码
上图为网易云盾的滑动拼图验证码,其应该有一个专门的图片库,裁剪的位置是固定的.我的想法是,随机生成图片,随机生成位置,再用canvas裁剪出滑块和背景图.下面介绍具体步骤. 首先随便找一张图片渲染到c ...
- 用C#语言编写:数组分析器
static void Main(string[] args) { #region 创建数组 Console.Write("请输入数 ...
- Mycat 读写分离详解
Mycat 的读写分离是依赖数据库级别的数据主从同步的基础上来实现的(Mysql 的主从配置链接),Mycat 的读写分离是在 schema.xml 配置的 dataHost 节点的 balance ...
- Mycat 配置说明(rule.xml)
rule.xml 配置文件定义了我们对表进行拆分所涉及到的规则定义.我们可以灵活的对表使用不同的分片算法, 或者对表使用相同的算法但具体的参数不同. tableRule 标签 该标签用于定义表的拆分规 ...