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