由类名创建对象(转)

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

要想实现这一点,必须有一个 管理中心 ,用于登记类的名字,并且通过名字能够调用某个方法来创建相应的类。结合类工厂的设计思想,这里我们让一套 继承体系中的基类作为 管理中心 ,由它来维护所有派生类的必要信息,包括类名和工厂函数,这二者必须建立起映射关系,map 是不错的选择。定义了一个派 生类后,它就自动向基类进行注册,可是如何实现自动呢?先看看程序吧:

// 为编写方便,下面的代码都位于.cpp 文件中
#ifdef _MSC_VER
#pragma warning (disable: 4786)
#endif
#include <iostream>
#include <map>
using namespace std ;

class Base
{
public :
    virtual void Print() //
测试用
     {
         cout << "This is Base" << endl;
     }
protected :
    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; //
存储子类信息
};

map<const char *, Base::ClassGen> Base::class_set; //
静态成员变量定义

class Derived : public Base
{
public :
    struct DerivedRegister //
辅助类,用于注册
     {
         DerivedRegister()
         { //
注册子类,虽然map 能保证唯一,但仍只注册一次
            static bool bRegistered = false ;
            if (!bRegistered)
             {
                 Base::Register ("Derived" , Derived::Create); //
注册子类信息
                 bRegistered = true ;
             }
         }    
     };
    static Base* Create() //
工厂函数
     {
        return new Derived;
     }
public :
    virtual void Print() //
测试用
     {
         cout << "This is Derived" << endl;
     }
};

static Derived::DerivedRegister Derived_for_registering; //
没有其它机制能够保证在全局空间调用注册函数,
//
不得已,定义一个全局变量来完成这项光荣的任务,看起来有点龌龊

int main()
{
     Base* pDerived = Base::Create("Derived" ); //
类名可以动态输入
    if (pDerived) pDerived->Print(); //
创建成功调用虚函数
    else cout << "Create error" << endl;
     system("pause" );
    return 0;
}

上面这样实现,有的朋友可能觉得使用起来很麻烦,实际上我们用宏定义来改造一下就会非常漂亮,代码呆会儿就会看到。还是说说自动注册功能吧,首先, 为什么要实现自动注册呢?这是为了最大程度上隐藏实现,实际上采用手动注册也可以,只不过我们得在主函数里一一调用每个类的注册函数。那我们是如何实现自 动注册的呢?方法是将注册代码放到一个辅助类的构造函数中,然后定义一个该类的静态全局变量,这样构造函数便被调用了,:) ,缺点是多了一个额外的对象, 除了用于注册外,它什么用也没有(最初我没有采用辅助类,而是直接在派生类的构造函数中注册,然后定义派生类的全局变量,这样明显会浪费空间,采用辅助类 便将额外开销降低到了最小)。

下面让我们瞧瞧用宏改造后的模样:

#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;
}

上面的宏定义可以重复利用(是不是有点似曾相识,是的,MFC 中在对序列化和动态创建等支持时用到了类似的宏),在使用的时候,只需简单的使用这四个宏,即可实现动态创建,感觉还不错吧,不过提醒一点,其中的两个IMPLEMENT 宏都应该放在.cpp 文件中。

这种方法还是存在一些缺点的,不过本文主要是提供一种思路,可以根据具体的情况再作相应变动。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值