C++实现类似反射模式
在编写遥感算法工具箱的时候,工具都是在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; }