C++ 反射

概念:

    反射机制允许程序在运行时借助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;
};

}
}

      

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

水火汪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值