• 动态类(类工厂)总结


    动态类(类工厂)总结

    一、动态类的作用

    动态类应用的一个类似的例子便是MFC中CWnd类的Create方法,其第一个参数为Window Class的名字,这就允许用户通过class的名字来创建相应的窗口。C++不是动态语言,所以没法从语言机制上实现类的动态创建,但很明显这样的需求是存在的。

    要想实现这一点,必须有一个“管理中心”,用于登记类的名字,并且通过名字能够调用某个方法来创建相应的类。结合类工厂的设计思想,这里我们让一套继承体系中的基类作为“管理中心”,由它来维护所有派生类的必要信息,包括类名和工厂函数,这二者必须建立起映射关系,map是不错的选择。

    二、动态类原理

    1、  基本原理

    动态类就是给基类定义一个静态的map,如下例:

    static map<const char*, ClassGen> class_set;

    这样,没一个新建的类都可以被记录在这个map表中,而且也便于程序根据名称来调用响应的类。

    其他的部分都是围绕着这个map运行的,都是对map进行增加、查找之类的操作。

    使用宏定义,可以加快程序的响应速度。

    动态类的实现,代码并不唯一,功能也不仅限于此。不过下面实现的简单的动态类会给我们很大的参考价值。

    2、宏定义的小知识

    代码中每个行末都有“”这是要把行末的换行符号转译掉,避免他影响宏定义。“##”符号在宏定义中起到一个连接的作用,比如

    #define FUN(var) var##ing

    最后FUN(str)的结果就是string。

    在宏定义中“#”代表的取变量的值,比如

    #define FUN(var) #var

    string str = FUN(string);

    str的值就是“string”,如果没有#,翻译之后的语句就是 string str = string这样会出现错误。

    3、 源码分析

    在动态类创建过程中,只需要使用以下四个语句:

    DECLARE_DYNCRT_BASE(Base) // 声明动态基类
    DECLARE_DYNCRT_CLASS(Derived, Base) // 声明动态类

    IMPLEMENT_DYNCRT_BASE(Base) // 实现动态基类
    IMPLEMENT_DYNCRT_CLASS(Derived) // 实现动态类
    后面的两个实现,就是两个变量定义,主要说前面两个语句,在下面的代码中可以用一个语句概括:

    base::Register(#derived, Create);

    这个语句在动态派生类中,意思就是调用动态基类的Register函数,第一个#derived是取动态派生类的类名,Create是调用动态派生类的自己的创建函数返回动态基类类型的一个指针,实际上这个指针式指向派生类的。

    因为是宏定义的形式,所以在main函数运行之前,这些操作早就已经完成了。

    另外,程序编译的过程如下:

    C源程序头文件-->预编译处理(cpp)-->编译程序本身-->优化程序-->汇编程序-->链接程序-->可执行文件

    三、动态类源码解析

    #ifdef _MSC_VER
    #pragma warning(disable: 4786)
    #endif
    #include <iostream>
    #include <map>
    using namespace std;
    
    // 用于声明具有动态创建功能的基类 
    #define DECLARE_DYNCRT_BASE(base) 
    public: 
        typedef base* (*ClassGen)(); 
        static void Register(const char* class_name, ClassGen class_gen) 
        { 
            class_set.insert(map<const char*, ClassGen>::value_type(class_name, class_gen)); 
        } 
    public: 
        static base* Create(const char* class_name) 
        { 
            map<const char*, ClassGen>::iterator iter; 
            if((iter = class_set.find(class_name)) != class_set.end()) 
            { 
                return ((*iter).second)(); 
            } 
            return NULL; 
        } 
    protected: 
        static map<const char*, ClassGen> class_set; 
    
    // 用于实现基类 
    #define IMPLEMENT_DYNCRT_BASE(base) 
    map<const char*, base::ClassGen> base::class_set;
    
    // 用于声明一个能够被动态创建的类 
    #define DECLARE_DYNCRT_CLASS(derived, base) 
    public: 
        struct derived##Register 
        { 
            derived##Register() 
            { 
                static bool bRegistered = false; 
                if(!bRegistered) 
                { 
                    base::Register(#derived, Create); 
                    bRegistered = true; 
                } 
            } 
        }; 
        static base* Create() 
        { 
            return new derived; 
        }
    
    // 用于实现一个能够被动态创建的类  
    #define IMPLEMENT_DYNCRT_CLASS(derived) 
    static derived::derived##Register derived##_for_registering; 
    
    // 测试
    class Base
    {
        DECLARE_DYNCRT_BASE(Base) // 声明动态基类 
        DECLARE_DYNCRT_CLASS(Base, Base) // 基类自己也可以动态创建 
    public:
        virtual void Print() 
        {
            cout << "This is Base" << endl;
        }
    };
    
    IMPLEMENT_DYNCRT_BASE(Base) // 实现动态基类 
    IMPLEMENT_DYNCRT_CLASS(Base) // 实现动态类
    
    class Derived : public Base
    {
        DECLARE_DYNCRT_CLASS(Derived, Base) // 声明动态类 
    public:
        virtual void Print() 
        {
            cout << "This is Derived" << endl;
        }
    };
    
    IMPLEMENT_DYNCRT_CLASS(Derived) // 实现动态类
    
    int main()
    {
        Base* pBase = Base::Create("Base"); // 类名可以动态输入
        if(pBase) pBase->Print(); // 创建成功调用虚函数
        else cout << "Create Base error" << endl;
        
        Base* pDerived = Base::Create("Derived"); // 类名可以动态输入
        if(pDerived) pDerived->Print(); // 创建成功调用虚函数
        else cout << "Create Derived error" << endl;
        
        system("pause");
        return 0;
    }
    

      

  • 相关阅读:
    ffmepg m3u8转mp4 Invalid data found when processing input
    使用FFmpeg 将m3u8视频格式转换成MP4示例
    ASP.NET Core 中的 Request Feature
    Advanced .NET Remoting: 第 8 章 创建连接器
    Advanced .NET Remoting: 第 9 章 4.改变编程模型
    Advanced .NET Remoting: 第 9 章 3.在 Remoting 中传递额外的运行时信息
    Flink KeyBy分布不均匀问题及解决方法
    Module compiles, but editor shows compilation issues
    【转】VirtualBox网络之仅主机(HostOnly)网络
    【转】VirtualBox配置双网卡实现宿主机和虚拟机相互访问及网络互通
  • 原文地址:https://www.cnblogs.com/bugutian/p/4490916.html
Copyright © 2020-2023  润新知