概念:
反射机制允许程序在运行时借助Reflection API 取得任何类的内部信息,并能直接操作对象的内部属性和方法。
问题:
1:c++不支持反射
2:很多业务场景需要依赖反射机制,比如rpc、web mvc 、对象序列化。
目标:
类对象的反射
类成员数据的反射
类成员函数的反射
用法:
#include <iostream>
using namespace std;
#include "ClassFactory.h"
using namespace yazi::reflect;
#include "test/A.h"
int main()
{
ClassFactory * factory = Singleton<ClassFactory>::instance();
Object * a = factory->create_class("A");
string name;
a->get("m_name", name);
a->set("m_name", "kitty");
int age;
a->get("m_age", age);
a->set("m_age", 30);
a->call("f1");
int num = a->call<int>("f2", 123);
return 0;
}
类对象的反射:
先创建下模板单例类
Singleton.h
#pragma once
namespace yazi {
namespace utility {
template <typename T>
class Singleton
{
public:
static T * instance()
{
if (m_instance == NULL)
m_instance = new T();
return m_instance;
}
private:
Singleton() {}
Singleton(const Singleton<T> &);
Singleton<T> & operator = (const Singleton<T> &);
~Singleton() {}
private:
static T * m_instance;
};
template <typename T>
T * Singleton<T>::m_instance = NULL;
}}
ClassFactory.h
#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <functional>
using namespace std;
#include "Singleton.h"
using namespace yazi::utility;
#include "ClassField.h"
#include "ClassMethod.h"
namespace yazi {
namespace reflect {
class Object
{
public:
Object();
virtual ~Object();
void set_class_name(const string & className);
const string & get_class_name() const;
int get_field_count();
ClassField * get_field(int pos);
ClassField * get_field(const string & fieldName);
template <typename T>
void get(const string & fieldName, T & value);
template <typename T>
void set(const string & fieldName, const T & value);
void set(const string & fieldName, const char * value);
template <typename R = void, typename ...Args>
R call(const string & methodName, Args... args);
private:
string m_className;
};
typedef Object * (*create_object)(void);
class ClassFactory
{
friend class Singleton<ClassFactory>;
public:
// reflect class
void register_class(const string & className, create_object method);
Object * create_class(const string & className);
// reflect class field
void register_class_field(const string & className, const string & fieldName, const string & fieldType, size_t offset);
int get_class_field_count(const string & className);
ClassField * get_class_field(const string & className, int pos);
ClassField * get_class_field(const string & className, const string & fieldName);
// reflect class method
void register_class_method(const string & className, const string &methodName, uintptr_t method);
int get_class_method_count(const string & className);
ClassMethod * get_class_method(const string & className, int pos);
ClassMethod * get_class_method(const string & className, const string & methodName);
private:
ClassFactory() {}
~ClassFactory() {}
private:
std::map<string, create_object> m_classMap;
std::map<string, std::vector<ClassField *>> m_classFields;
std::map<string, std::vector<ClassMethod *>> m_classMethods;
};
template <typename T>
void Object::get(const string & fieldName, T & value)
{
ClassField * field = Singleton<ClassFactory>::instance()->get_class_field(m_className, fieldName);
size_t offset = field->offset();
value = *((T *)((unsigned char *)(this) + offset));
}
template <typename T>
void Object::set(const string & fieldName, const T & value)
{
ClassField * field = Singleton<ClassFactory>::instance()->get_class_field(m_className, fieldName);
size_t offset = field->offset();
*((T *)((unsigned char *)(this) + offset)) = value;
}
template <typename R, typename ...Args>
R Object::call(const string & methodName, Args... args)
{
ClassFactory * factory = Singleton<ClassFactory>::instance();
ClassMethod * method = factory->get_class_method(m_className, methodName);
auto func = method->method();
typedef std::function<R(decltype(this), Args...)> class_method;
return (*((class_method *)func))(this, args...);
}
}
}
ClassFactory.cpp
#include "ClassFactory.h"
using namespace yazi::reflect;
Object::Object() : m_className("")
{
}
Object::~Object()
{
}
void Object::set_class_name(const string & className)
{
m_className = className;
}
const string & Object::get_class_name() const
{
return m_className;
}
int Object::get_field_count()
{
return Singleton<ClassFactory>::instance()->get_class_field_count(m_className);
}
ClassField * Object::get_field(int pos)
{
return Singleton<ClassFactory>::instance()->get_class_field(m_className, pos);
}
ClassField * Object::get_field(const string & fieldName)
{
return Singleton<ClassFactory>::instance()->get_class_field(m_className, fieldName);
}
void Object::set(const string & fieldName, const char * value)
{
ClassField * field = Singleton<ClassFactory>::instance()->get_class_field(m_className, fieldName);
size_t offset = field->offset();
*((string *)((unsigned char *)(this) + offset)) = string(value);
}
void ClassFactory::register_class(const string & className, create_object method)
{
m_classMap[className] = method;
}
Object * ClassFactory::create_class(const string & className)
{
auto it = m_classMap.find(className);
if (it == m_classMap.end())
{
return nullptr;
}
return it->second();
}
void ClassFactory::register_class_field(const string & className, const string & fieldName, const string & fieldType, size_t offset)
{
m_classFields[className].push_back(new ClassField(fieldName, fieldType, offset));
}
int ClassFactory::get_class_field_count(const string & className)
{
return m_classFields[className].size();
}
ClassField * ClassFactory::get_class_field(const string & className, int pos)
{
int size = m_classFields[className].size();
if (pos < 0 || pos >= size)
{
return nullptr;
}
return m_classFields[className][pos];
}
ClassField * ClassFactory::get_class_field(const string & className, const string & fieldName)
{
auto fields = m_classFields[className];
for (auto it = fields.begin(); it != fields.end(); it++)
{
if ((*it)->name() == fieldName)
{
return *it;
}
}
return nullptr;
}
void ClassFactory::register_class_method(const string & className, const string &methodName, uintptr_t method)
{
m_classMethods[className].push_back(new ClassMethod(methodName, method));
}
int ClassFactory::get_class_method_count(const string & className)
{
return m_classMethods[className].size();
}
ClassMethod * ClassFactory::get_class_method(const string & className, int pos)
{
int size = m_classMethods[className].size();
if (pos < 0 || pos >= size)
{
return nullptr;
}
return m_classMethods[className][pos];
}
ClassMethod * ClassFactory::get_class_method(const string & className, const string & methodName)
{
auto methods = m_classMethods[className];
for (auto it = methods.begin(); it != methods.end(); it++)
{
if ((*it)->name() == methodName)
{
return *it;
}
}
return nullptr;
}
其中ClassFactory中有个友元类Singleton,这样Singleteon就可以调用ClassFactory工厂类中的api了。
其中ClassRegister.h 是注册类、注册元素、和注册方法的类。类中获取单列类Singleton的接口,在用此接口依次注册类、元素、方法。
ClassRegister.h:
#pragma once
#include "ClassFactory.h"
namespace yazi {
namespace reflect {
class ClassRegister
{
public:
ClassRegister(const string & className, create_object method)
{
// register class
Singleton<ClassFactory>::instance()->register_class(className, method);
}
ClassRegister(const string & className, const string & fieldName, const string & fieldType, uintptr_t offset)
{
// register class field
Singleton<ClassFactory>::instance()->register_class_field(className, fieldName, fieldType, offset);
}
ClassRegister(const string & className, const string & methodName, uintptr_t method)
{
// register class method
Singleton<ClassFactory>::instance()->register_class_method(className, methodName, method);
}
};
#define REGISTER_CLASS(className) \
Object * createObject##className() \
{ \
Object * obj = new className(); \
obj->set_class_name(#className); \
return obj; \
} \
ClassRegister classRegister##className(#className, createObject##className)
#define REGISTER_CLASS_FIELD(className, fieldName, fieldType) \
className className##fieldName; \
ClassRegister classRegister##className##fieldName(#className, #fieldName, #fieldType, (size_t)(&(className##fieldName.fieldName)) - (size_t)(&className##fieldName))
#define REGISTER_CLASS_METHOD(className, methodName, returnType, ...) \
std::function<returnType(className *, ##__VA_ARGS__)> className##methodName##method = &className::methodName; \
ClassRegister classRegister##className##methodName(#className, #methodName, (uintptr_t)&(className##methodName##method))
}
}
其中REGISTER_CLASS(className)宏主要做两件事,一:创建classname的对象函数,调用ClassRegister向工厂类中注册。
要注册的类:
#pragma once
#include <string>
using namespace std;
#include "ClassRegister.h"
using namespace yazi::reflect;
class A : public Object
{
public:
A() : m_name("a"), m_age(18) {}
void f1()
{
std::cout << "f1" << std::endl;
}
int f2(int a)
{
std::cout << "f2" << std::endl;
return a;
}
public:
string m_name;
int m_age;
};
REGISTER_CLASS(A);
REGISTER_CLASS_FIELD(A, m_name, string);
REGISTER_CLASS_FIELD(A, m_age, int);
REGISTER_CLASS_METHOD(A, f1, void);
REGISTER_CLASS_METHOD(A, f2, int, int);
类成员数据的反射:
关键问题:如何获取类成员数据的内存地址偏移量。
下面是具体的两种方法。
#define OFFSET(className, fieldName) \
((size_t)(&((className *)0)->fieldName))
Test t;
size_t offset = (size_t)(&(t.member)) - (size_t)(&t);
ClassField.h
#pragma once
#include <string>
using namespace std;
namespace yazi {
namespace reflect {
class ClassField
{
public:
ClassField() : m_name(""), m_type(""), m_offset(0) {}
ClassField(const string & name, const string & type, size_t offset) : m_name(name), m_type(type), m_offset(offset) {}
~ClassField() {}
const string & name()
{
return m_name;
}
const string & type()
{
return m_type;
}
size_t offset()
{
return m_offset;
}
private:
string m_name;
string m_type;
size_t m_offset;
};
}
}
类成员函数的反射:
ClassMethod.h:
#pragma once
#include <string>
using namespace std;
namespace yazi {
namespace reflect {
class ClassMethod
{
public:
ClassMethod() : m_name(""), m_method(0) {}
ClassMethod(const string & name, uintptr_t method) : m_name(name), m_method(method) {}
~ClassMethod() {}
const string & name()
{
return m_name;
}
uintptr_t method()
{
return m_method;
}
private:
string m_name;
uintptr_t m_method;
};
}
}