博主在写程序时遇到了需要运用XML根据类名去动态的创建类对象的问题。这个方式在拥有反射机制的语言中很好实现,例如JAVA,但是C++没有反射机制。不过强大的C++允许我们自己实现伪反射。
下面上博主自己写的一个实现伪反射的C++代码:
ClassFactory.h
#pragma once
#include <map>
#include <iostream>
#include <string>
using namespace std;
#define REGISTER(ClassName) \
ClassName* ObjectCreator##ClassName(){ \
return new ClassName; \
} \
RegisterAction CreatorRegister##ClassName( \
#ClassName,(CreateObject)ObjectCreator##ClassName)
typedef void* (*CreateObject)(void); //函数指针
class ClassFactory
{
private:
map<string, CreateObject> m_classMap ;
ClassFactory(){}; //构造函数私有化
public:
void* GetClassByName(string className);
void RegistClass(string name, CreateObject method) ;
static ClassFactory& GetInstance() ;
};
class RegisterAction
{
public:
RegisterAction(string ClassName,CreateObject CreateOb)
{
ClassFactory::GetInstance().RegistClass(ClassName,CreateOb);
}
};
ClassFactory.cpp
#include "ClassFactory.h"
void* ClassFactory::GetClassByName(string ClassName)
{
map<string, CreateObject>::const_iterator iter = m_classMap.find(ClassName);
if ( iter == m_classMap.end() )
{
return NULL ;
}
else
{
return iter->second() ;
}
}
void ClassFactory::RegistClass(string name, CreateObject method)
{
m_classMap.insert(pair<string, CreateObject>(name, method)) ;
}
ClassFactory& ClassFactory::GetInstance()
{
static ClassFactory sLo_factory;
return sLo_factory ;
}
如此便实现了伪反射。
下面博主带大家分析代码。
首先博主为大家讲解实现思想,大家可以参考上面的整体代码来看下面的局部代码,以下代码只放出声明用于讲解思想,想知道实现请看上面的ClassFactory.cpp。
1.写一个类,这个类中有一个私有的键值对数据,用于存储你需要创建的类对象的类名以及创建该类对象的函数指针。如此我们便可以根据类名去动态的创建类对象了!
class ClassFactory
{
private:
map<string, CreateObject> m_classMap ;
ClassFactory(){}; //构造函数私有化
public:
void* GetClassByName(string className);
void RegistClass(string name, CreateObject method) ;
static ClassFactory& GetInstance() ;
};
2.我们需要再写一个类用于将你需要创建的类对象的类名以及创建该类对象的函数指针存储进键值对中。
class RegisterAction
{
public:
RegisterAction(string ClassName,CreateObject CreateOb)
{
ClassFactory::GetInstance().RegistClass(ClassName,CreateOb);
}
};
3.因为我们每一个类都应该有一个创建该类对象的函数,并有一个函数指针指向该函数,并且将这个类的类名与该函数指针添加到键值对中。在编程中重复是大忌,因为每个类都要进行此操作,因此,博主将其抽象出来运用宏去解决。
#define REGISTER(ClassName) \
ClassName* ObjectCreator##ClassName(){ \
return new ClassName; \
} \
RegisterAction CreatorRegister##ClassName( \
#ClassName,(CreateObject)ObjectCreator##ClassName)
typedef void* (*CreateObject)(void); //函数指针
如此便完成了思想的讲解。
那么大家应该如何使用博主写的库文件呢?
大家只需要在自己的工程中添加博主的ClassFactory.h和ClassFactory.cpp文件。然后在自己需要根据类名动态创建的类的实现.cpp文件中后写上REGISTER(类名)就可以了,例如:
#include "CTriangle.h"
int CTriangle::show()
{
cout << " " << endl;
return 0;
}
REGISTER(CTriangle);
然后在实际运用中只需要从XML中提取出类名就可以动态的创建类对象啦!如下代码所示:(博主在这里使用的是tinyXML2解析库。)
int ClassPrint()
{
list<CShape*> temp;
tinyxml2::XMLDocument doc;
if(doc.LoadFile("ClassXML.xml") != 0)
{
cout << "加载XML文件失败" << endl;
system("pause");
exit(0);
}
tinyxml2::XMLElement* root = doc.RootElement();
tinyxml2::XMLElement* RSquare = root->FirstChildElement();
while(RSquare)
{
CShape* PCShape = (CShape*)ClassFactory::GetInstance().GetClassByName(RSquare->GetText());
if(PCShape != NULL)
{
temp.push_back(PCShape);
}
RSquare = RSquare->NextSiblingElement();
}
return 0;
}
是不是很简单呢?有帮助的话点个赞吧!有问题的话欢迎大家在评论区批评指正。