• C++类对象反制机制实现_精简修改版


    前几天写的类对象反射机制太烦锁了,今天写个修改版的,精简为两个类
    一个是类的数据结构,另一个是类的父类对象,把所有操作类的方法都写到父类中

    1.类的信息结构体

    struct Field_Node
    {
    	TCHAR m_name[20];		//字段名称
    	TCHAR m_typeName[20];	// 字段类型名称
    	size_t m_typeHashCode;	//字段数据类型的哈希值
    	size_t m_typeOffs;		//字段偏移量
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    字段信息结构不再添加其他方法了,就只为保存字段信息数据

    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
    	}
    
    
    	
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    这样就能对子类对象的字段进行数据操作了

    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() 获得数据类型的哈希值,用来比较数据类型是否相同
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    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;
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    总结一下是不是比前面[写的简单多了,也容易弄懂,
    其实关键是获取子类的结构信息,用纯虚函数就能调用子类的静态字段结构数组,
    也就相对简单了,

  • 相关阅读:
    web-3(httpd2.4)
    学术论文中的Introduction与Background
    欧拉图和哈密顿图
    微信小程序--事件
    [⑤ADRV902x]: TES (Transceiver Evaluation Software) 使用
    微服务系列之网关(二) konga配置操作
    Vue进阶(幺陆玖)项目部署后IE报 SCRIPT1002:语法错误 解决方案探讨
    springboot+jsp高校学生宿舍管理系统-宿管带前端
    购物单 机试题
    【M365运维】给从本地同步到O365的DL添加 Send As权限
  • 原文地址:https://blog.csdn.net/qq_31178679/article/details/134083267