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( ...
随机推荐
- 【Uoj34】多项式乘法(NTT,FFT)
[Uoj34]多项式乘法(NTT,FFT) 题面 uoj 题解 首先多项式乘法用\(FFT\)是一个很久很久以前就写过的东西 直接贴一下代码吧.. #include<iostream> # ...
- 【Luogu3919】可持久化数组(主席树)
题面戳我 题解 放一个板子在这里 用主席树维护一下每个版本就可以啦... #include<iostream> #include<cstdio> #include<cst ...
- [HNOI2008]水平可见直线
按斜率排序后画个图,用单调栈维护这个半平面交 # include <bits/stdc++.h> # define IL inline # define RG register # def ...
- vue 父组件与子组件的通信
参考博客地址:http://www.cnblogs.com/okaychen/p/7674211.html,很详细!
- 在windows10上配置Android的环境变量
一, 首先右击"我的计算机"或"此电脑"图标,在弹出来的下拉列表中点击"属性(R)",进入到"系统"属性面板,点击左侧的 ...
- c#多线程同步之lock
一提起lock,想必大家都很熟悉,因为它易用,顾名思义,就是一把锁,常用于多线程的同步,一次只允许一个线程进入.最近遇到一个很诡异的bug. private static readonly objec ...
- mysql的下载安装
不知道为什么,写这篇文章我总是想感慨一下.首先我的感谢和敬佩那些能把知识和技术分享出来的开发者,不管你的技术是否很牛,但是你的精神让我十分敬佩.学java的已经二天了,除了问问朋友,给我最大帮助的就是 ...
- Cassandra配置多节点集群以及使用雅虎YCSB压测Cassandra 3.11
这几天在搭Cassandra集群以及对Cassandra的性能测试,步骤还挺多,记录一下. 关于Caaandra在服务器上配置多节点集群,可以参考一下文章: http://blog.csdn.net/ ...
- Hibernate 一对一关联映射,mappedBy参数解析
在最近java,SSH框架的学习中遇到了这样的一个问题,在Hibernate的开发中一对一关联映射的单向关联,主表会在次表新增一列次表的主键如下图,但是在双向关联中次表不会在表中创建主表的主键一列,这 ...
- 1-1hibernate数据库操作基础
一.纯原始数据库连接详见http://www.cnblogs.com/lukelook/p/7845757.html 1.Class.forName("oracle.jdbc.driver. ...