• 定制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 = 0; 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 = 0; 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 = 0; 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: 2227
    static_cast from A to C: 00000202D48C9FE0, Time: 0
    fast_dynamic_cast from A to C: 00000202D48C9FE0, Time: 199

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

        cout << "
    ===== cast from pointer A to pointer B, should be not null =====" << endl;
    
        B* b = nullptr;
        start = clock();
        for (int i = 0; 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 = 0; 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 = 0; 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: 2927
    static_cast from A to B: compiler error
    fast_dynamic_cast from A to B: 000001D65F2FA308, Time: 208

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

        cout << "
    ===== cast from pointer A to pointer D, should be null =====" << endl;
    
        D* d = nullptr;
        start = clock();
        for (int i = 0; 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 = 0; 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 = 0; 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: 0000000000000000, Time: 3534
    static_cast from A to D: 0000026050C6D310, Time: 0
    fast_dynamic_cast from A to D: 0000000000000000, Time: 227

    总结:根据以上测试结果,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 = 100000000;
    
        cout << "===== cast from pointer A to pointer C, should be not null =====" << endl;
    
        C* c = nullptr;
        start = clock();
        for (int i = 0; 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 = 0; 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 = 0; 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 << "
    ===== cast from pointer A to pointer B, should be not null =====" << endl;
    
        B* b = nullptr;
        start = clock();
        for (int i = 0; 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 = 0; 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 = 0; 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 << "
    ===== cast from pointer A to pointer D, should be null =====" << endl;
    
        D* d = nullptr;
        start = clock();
        for (int i = 0; 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 = 0; 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 = 0; 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 0;
    }
    View Code
  • 相关阅读:
    做个商城吧在(一)前端架构概要
    我的前端工具集(二)文件上传的封装
    一点一点看JDK源码(六)java.util.LinkedList前篇之链表概要
    [Architect] Abp 框架原理解析(4) Validation
    [Architect] Abp 框架原理解析(3) DynamicFilters
    [Architect] Abp 框架原理解析(2) EventBus
    [Architect] Abp 框架原理解析(1) Module
    [Solution] AOP原理解析及Castle、Autofac、Unity框架使用
    [Solution] DI原理解析及Castle、Unity框架使用
    [Architect] ABP(现代ASP.NET样板开发框架) 翻译
  • 原文地址:https://www.cnblogs.com/ldlchina/p/8698346.html
Copyright © 2020-2023  润新知