C++实现类似反射模式

在编写遥感算法工具箱的时候,工具都是在xml文件中配置好的,在工具箱上构建一棵树根据xml配置文件,然后通过双击不同的树节点,弹出不同的算法对话框。最简单的方式就是使用if else 或者switch case之类的条件判断语句来实现,但是这个太不方便了,每增加一个算法,都要在分支上添加一个条件谈判,用现在流行的话说就是太不给力了。于是想通过一个比较通用的方式来解决这个问题。

image

    由于我的算法对话框都是基于MFC的CDialog,所以可以通过算法对话框的类名来创建各自的对象,然后将对话框显示。以前知道在Java和C#中有一个反射模式,就是可以通过类名来创建一个类的对象。但是C++是没有这个东东的,于是就查找资料,终于用C++的模板实现了类似的功能。下面贴代码:

/** /file RegistClassName.h 
* 图像数据处理对话框反射模式
*/

#ifndef REGISTCLASSNAME_H
#define REGISTCLASSNAME_H

#include 
#include 
#include 
using namespace std;


/**
* @brief 重定义对象
*/
typedef CDialog*(*pf)();

/**
* /class ClassMap RegistClassName.h 
* @brief 类映射
*/
class ClassMap
{
private:
    /**
    * @brief 私有构造函数
    * 为了让这个类不产生实例对象
    */
    ClassMap() { }

    /**
    * @brief 以类名为键的一个存放着构建方法的Hash表
    */
    static map<string, pf> m_ClassMap;
    
public:
    /**
    * @brief 定义一个类必须注册一下
    * @param _className 类名
    * @param _createFun 注册函数指针
    */
    static void RegistClass(string _className, pf _createFun)
    {
        if(m_ClassMap.find(_className) != m_ClassMap.end())
            return; //已经注册过,直接返回

        m_ClassMap[_className] = _createFun;
    }

    /**
    * @brief 私有构造函数
    * @param _className 类名
    */
    static CDialog* forName(string _className)
    {
        if(m_ClassMap.find(_className) == m_ClassMap.end())
            return NULL;    //没有找到类对象,返回NULL
        else
            return (m_ClassMap[_className])();
    }
};

/**
* @brief 以类名为键的一个存放着构建方法的Hash表
*/
__declspec(selectany) map<string, pf> ClassMap::m_ClassMap;

/**
* /class DelegatingObject RegistClassName.h 
* @brief 委派模板类
*/
template<typename T>
class DelegatingObject 
{
public:
    /**
    * @brief 构造函数
    * @param _className 类名
    */
    DelegatingObject(string _className)
    {
        ClassMap::RegistClass(_className, &(DelegatingObject::Create));
    }

    /**
    * @brief 创建实例函数
    */
    static CDialog* Create()
    {
        return static_cast<CDialog*>(new T);
    }
};

/**
* @brief 注册类的宏定义
*/
#ifndef REGIST_CLASS
#define REGIST_CLASS(X) DelegatingObject<X> __class_##X( #X );
#endif

#endif //REGISTCLASSNAME_H

这样只要在各自的算法对话框的Cpp文件前面添加下面一句话即可:

REGIST_CLASS(CRasterTransformDlg); //栅格文件格式转换
REGIST_CLASS(CVectorTransformDlg); //矢量文件格式转换

然后在调用算法的地方按照下面使用方法即可,这样就不用写一大批的if或者switch语句了:

BOOL ShowAlgoDialog(string strDlgName) 
{ 
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    CDialog * pDlg = (ClassMap::forName(strDlgName)); 

    if(pDlg == NULL) 
    { 
        AfxMessageBox("该类没有注册,请检查!",MB_OK);
        return FALSE; 
    }
    
    pDlg->DoModal();
    return TRUE;
}
posted @ 2013-10-25 09:04  vstion  阅读(1064)  评论(1编辑  收藏  举报