前几天写的类对象反射机制太烦锁了,今天写个修改版的,精简为两个类
一个是类的数据结构,另一个是类的父类对象,把所有操作类的方法都写到父类中
1.类的信息结构体
struct Field_Node
{
TCHAR m_name[20]; //字段名称
TCHAR m_typeName[20]; // 字段类型名称
size_t m_typeHashCode; //字段数据类型的哈希值
size_t m_typeOffs; //字段偏移量
};
字段信息结构不再添加其他方法了,就只为保存字段信息数据
2.父类QObject
class QObject
{
public:
QObject(){}
virtual ~QObject(){}
public:
//静态方法获取子类对象,直接New一个子类对象就好了
template<typename T>
static QObject* CreateObject(){
retrun new T();
}
//纯虚函数获得子类的字段信息数组地址
virtual const Field_Node* GetSubClassFieldNode()const=0;
//设置类对象的字段数据
template<typename T>
void Set_Value(const TCHAR* strFieldName, const T& inValue){
//调用子类的,获得其静态的字段信息数组地址
const Field_Node* pField=GetSubClassFieldNode();
//循环查找字段名称并给其赋值
while(pField->m_typeHashCode!=0){
if(lstrcmp(pField->m_name,strFieldName)==0){
if(pField->m_typeHashCode!=typeid(T).hash_code()){
assert(false && "数据类型不匹配,检查字段数据类型和输入的数据类型是否一致!!!");
return;
}
//设置字段的值
*((T*)((unsigned char*)&stu+ pField->m_typeOffs))=inValue;
return;
}
pField++;
}//end while
}
//获得字段数据
void Get_Value(const TCHAR* strFieldName, T& outValue){
//调用子类的,获得其静态的字段信息数组地址
const Field_Node* pField=GetSubClassFieldNode();
//循环查找字段名称并给其赋值
while(pField->m_typeHashCode!=0){
if(lstrcmp(pField->m_name,strFieldName)==0){
if(pField->m_typeHashCode!=typeid(T).hash_code()){
assert(false && "数据类型不匹配,检查字段数据类型和输入的数据类型是否一致!!!");
return;
}
//获取字段的值
outValue=*((T*)((unsigned char*)&stu+ pField->m_typeOffs));
return;
}
pField++;
}//end while
}
};
这样就能对子类对象的字段进行数据操作了
3.下面是类的注册宏,在其内就重写一个父类的虚函数就搞定了,
//类内声明宏
#define REGISTER_CLASS_NAME()\
public:\
const Field_Node* GetSubClassFieldNode()const
//类外实现宏
#define BEGIN_REGISTER_FILEDS_NAME(class_name)\
const Field_Node* class_name::GetSubClassFieldNode()const{\
typedef class_name thisClass;\
static const Field_Node thisClass##Field_Node[]={\
//结束宏
#define END_REGISTER_FILEDS_NAME()\
{TEXT(""),TEXT(""),0,0}};return &thisClass##Field_Node[0];}
//添加字段信息结构宏
#define ADD_FIELD_NAME(fName,fType)\
{TEXT(#fName),TEXT(#fType),typeid(fType).hash_code(),(size_t)&((thisClass*)0)->fName},\
//TEXT(#fName) 字段名称(变量的名称,name,sex)
//TEXT(#fType) 数据类型名称(int ,bool)
//(size_t)&((thisClass*)0)->fName 字段的偏移量
//typeid(fType).hash_code() 获得数据类型的哈希值,用来比较数据类型是否相同
4.用法就更加简单了,
class Student :public QOBject{
REGISTER_CLASS_NAME()
public:
Student(){}
~Student(){}
public:
int id;
CString name;
CString sex;
UINT age;
};
BEGIN_REGISTER_FILEDS_NAME(Student)
ADD_FIELD_NAME(id, int)
ADD_FIELD_NAME(name, CString)
ADD_FIELD_NAME(sex, CString)
ADD_FIELD_NAME(age, UINT)
END_REGISTER_FILEDS_NAME()
//测试函数中
//通过父类的静态方法获取子类New的对象
//用父类指针来操作子类对象进行赋值,获取值等操作
QOject* pObj=QObject::CreateObject<Student>();
//给对象赋值
pObj->Set_Value(TEXT("id"),123);
pObj->Set_Value(TEXT("name"),CString(TEXT("张三")));
pObj->Set_Value(TEXT("sex"),CString(TEXT("男")));
pObj->Set_Value(TEXT("id"),(UINT)33);
//获取对象字段的值
Student s;
pObj->Get_Value(TEXT("id"),s.id);
pObj->Get_Value(TEXT("name"),s.name);
pObj->Get_Value(TEXT("sex"),s.sex);
pObj->Get_Value(TEXT("id"),s.age);
//最后操作完可转化子类对象指针
Student *pStu=(Student*)pObj;
总结一下是不是比前面[写的简单多了,也容易弄懂,
其实关键是获取子类的结构信息,用纯虚函数就能调用子类的静态字段结构数组,
也就相对简单了,