c++反射的实现

最直观的使用:通过类的名称、函数名称、变量名称来实现创建类、调用类函数、获取与修改类参数。

通过反射创建类

思路:使用工厂类来创建对应的类,这个工厂使用ClassMap 来保存每个类对应的创建函数。

  • 通过RegisterClass 向 mClassMap 中存储创建函数
  • 通过CreateClass 来查找并调用className 对应的创建函数CreateObject()
typedef Object* (*createObject)(void);

class ClassFactory final
{
    friend class Singleton<ClassFactory>; // 工厂类的单例
public:
    // 注册每个类的创建函数
    void RegisterClass(const std::string& className, createObject method);

    // 创建指定的类对象
    Object* CreateClass(const std::string& className);

protected:
     ClassFactory() = default;
    virtual ~ClassFactory() = default;

    ClassFactory(const ClassFactory& other) = delete;
    ClassFactory(ClassFactory&& other) noexcept = delete;
    ClassFactory& operator=(const ClassFactory& other) = delete;
    ClassFactory& operator=(ClassFactory&& other) noexcept = delete;
private:
    std::map<std::string, createObject> mClassMap; // ClassName -> create class object function
};

void ClassFactory::RegisterClass(const std::string& className, createObject method)
{
    mClassMap[className] = method;
}

Object* ClassFactory::CreateClass(const std::string& className)
{
    auto it = mClassMap.find(className);
    if (it == mClassMap.end() )
    {
        return nullptr;
    }
    return mClassMap[className]();
}

这个类创建工厂应该是全局唯一的,所以使用了单例模板

template<typename T, bool is_thread_safe = true>
class Singleton
{
public:
    static T* Instance()
    {
        if (!is_thread_safe)
        {
            if (!mInstance)
            {
                mInstance = new T();
            }
        }
        else
        {
            if (!mInstance)
            {
                std::lock_guard<std::mutex> unique_locker(mMutex);
                if (!mInstance)
                {
                    mInstance = new T();
                }
            }
        }
        return mInstance;
    }

    Singleton(const Singleton& other) = delete;
    Singleton& operator=(const Singleton& other) = delete;

protected:
    Singleton() = default;
    virtual ~Singleton() = default;

private:
    static T* mInstance;
    static std::mutex mMutex;
};

template<typename T, bool is_thread_safe>
T* Singleton<T, is_thread_safe>::mInstance;

template<typename T, bool is_thread_safe>
std::mutex Singleton<T, is_thread_safe>::mMutex;

可以看到CreateClass 的返回值为Object* ,Obejct 为所有需要使用c++反射的类的基类。

class Object
{
public:
    void SetClassName(const std::string& className)
    {
        mClassName = className;
    }

    /**
     * 测试用函数
     */
    void showClassName() const
    {
        std::cout << mClassName << std::endl;
    }
public:
    std::string mClassName;
};

之后每个需要通过反射创建的类,只需要继承Obejct 即可。同时,为了向ClassFactory 中注册每个类的信息,还需要一个注册宏来帮助每个类快捷的注册

class ClassRegister
{
public:
    // 通过构造函数来向工厂中注册类的信息
    ClassRegister(const std::string& className, createObject method)
    {
        Singleton<ClassFactory>::Instance()->RegisterClass(className, method);
    }
};

// 用于注册类的宏
#define REGISTER_CLASS(className)           \
    Object* createObject##className()       \
    {                                       \
        Object* obj = new className();      \
        obj->SetClassName(#className);    \
        return obj;                         \
    }                                       \
    ClassRegister classRegister##className(#className, createObject##className)

有了上面几个类之后,就可以快捷的创建可以用于反射创建的类

class A :public Object
{
};

REGISTER_CLASS(A);


class B : public Object
{
};

REGISTER_CLASS(B);

执行测试程序

int main(int argc, char* argv[])
{
    ClassFactory * factory = Singleton<ClassFactory>::Instance();
    Object* o1 = factory->CreateClass("A");
    o1->showClassName();
    Object* o2 = factory->CreateClass("B");
    o2->showClassName();
    return 0;
}

执行结果为

A
B
// 结果正确,已经可以通过反射实现类的创建

通过反射调用类的函数

定义一个保存类成员函数信息的类

class ClassMethod
{
public:
    ClassMethod() = default;
    ~ClassMethod() = default;
    ClassMethod(const std::string& name, uintptr_t method) : mName(name), mMethod(method){}

    const std::string& Name() {return mName;}
    const uintptr_t Method() {return mMethod;}

private:
    std::string mName;
    uintptr_t mMethod;
};

扩展ClassFactory来保存ClassMethod信息

// ClassFactory.h
class ClassFactory final
{
public:
    // 为className注册method
    void RegisterClassMethod(const std::string& className, ClassMethod* method);

    // 获取className类有多少个注册函数
    size_t GetClassMethodCount(const std::string& className);
    // 获取className在pos上对的函数
    ClassMethod* GetClassMethod(const std::string& className, size_t pos);
    // 获取className中methodName方法
    ClassMethod* GetClassMethod(const std::string& className, const std::string& methodName);
private:
    std::map<std::string, std::vector<ClassMethod*>> mClassMethods; // className -> classMethod
};

// ClassFactory.cpp
 
void ClassFactory::RegisterClassMethod(const std::string& className, ClassMethod* method)
{
    mClassMethods[className].push_back(method);
}

size_t ClassFactory::GetClassMethodCount(const std::string& className)
{
    return mClassMethods[className].size();
}

ClassMethod* ClassFactory::GetClassMethod(const std::string& className, size_t pos)
{
    const std::vector<ClassMethod*>& methods = mClassMethods[className];
    if (pos < 0 || pos >= methods.size())
    {
        return nullptr;
    }

    return methods[pos];
}

ClassMethod* ClassFactory::GetClassMethod(const std::string& className, const std::string& methodName)
{
    for (auto method : mClassMethods[className])
    {
        if (method->Name()._Equal(methodName))
        {
            return method;
        }
    }
    return nullptr;
}

扩展classRegister来注册ClassMethod信息

// ClassRegister.h
class ClassRegister
{
public:
    ClassRegister(const std::string& className, const std::string& methodName, uintptr_t method)
    {
        ClassFactory* factory = Singleton<ClassFactory>::Instance();
        factory->RegisterClassMethod(className, new ClassMethod(methodName, method));
    }
};

// 用于注册类成员函数的宏
#define REGISTER_CLASS_METHOD(className, methodName)    \
    std::function<void(className*)> className##methodName##method = &className::methodName; \
    ClassRegister classRegister##className##methodName(#className, #methodName, (uintptr_t)&(className##methodName##method))

扩展Object来通过反射方法调用ClassMethod

// Object.h
class Object
{
public:
void CallMethod(const std::string& methodName);
};

// Object.cpp
void Object::CallMethod(const std::string& methodName)
{
    ClassFactory* factory = Singleton<ClassFactory>::Instance();
    ClassMethod* classMethod = factory->GetClassMethod(mClassName, methodName);

    typedef std::function<void(decltype(this))> ClassFunctiuon;
    (*reinterpret_cast<ClassFunctiuon*>(classMethod->Method()))(this);
}

验证

class A :public Object
{
public:
    int ANum = 3;
    std::string AString = "this is a a test";
    std::vector<int> mVector;

    void pa()
    {
        std::cout << "this is a pa function" << std::endl;
    }
};
REGISTER_CLASS(A);
REGISTER_CLASS_METHOD(A, pa);

class B : public Object
{
public:

    int BNum = 2;
    std::string BString = "this is a b test";

    void pb()
    {
        std::cout << "this is a pb function" << std::endl;
    }
};
REGISTER_CLASS(B);
REGISTER_CLASS_METHOD(B, pb);

int main(int argc, char* argv[])
{
    ClassFactory* factory = Singleton<ClassFactory>::Instance();
    Object* a = factory->CreateClass("A");
    Object* b = factory->CreateClass("B");
    a->CallMethod("pa");
    b->CallMethod("pb");
}

结果为

this is a pa function
this is a pb function
// 结果正确,成功调用了方法

通过反射访问类的参数

如何直接访问一个类的参数呢,通过类的指针偏移,获取参数的地址,就可以访问了。所以这部分主要需要做的就是将类参数的指针偏移以及类型保存下来。

这里指针偏移可以直接调用标准库

class Test
{
int a = 0;
}

size_t offset = offsetof(Test, a); // 获取参数a的指针偏移

// 标准库内的定义
#if defined _MSC_VER && !defined _CRT_USE_BUILTIN_OFFSETOF
    #ifdef __cplusplus
        #define offsetof(s,m) ((::size_t)&reinterpret_cast<char const volatile&>((((s*)0)->m)))
    #else
        #define offsetof(s,m) ((size_t)&(((s*)0)->m))
    #endif
#else
    #define offsetof(s,m) __builtin_offsetof(s,m)
#endif

定义一个保存参数反射所需属性的类ClassFiled

// 记录类参数的反射信息
class ClassFiled
{
public:
    ClassFiled() = default;
    explicit  ClassFiled(const std::string& name, const std::string& type, size_t offset) : mName(name), mType(type), mOffset(offset){}
    virtual ~ClassFiled() = default;

    const std::string& Name() const {return mName;}
    const std::string& Type() const {return mType;}
    const size_t& Offset() const {return mOffset;}
private:
    std::string mName = "";
    std::string mType = "";
    size_t mOffset = 0;
};

拓展ClassFactory

// ClassFactory.h
class ClassFactory final
{
public:
    // 为className类注册字段
    void RegisterClassFiled(const std::string& className, ClassFiled* filed);

    // 获取className类有多少个注册的参数
    size_t GetFiledCount(const std::string& className);
    // 获取className类指定位置的参数信息
    ClassFiled* GetFiled(const std::string& className, size_t pos);
    // 获取className类的 filedName 参数
    ClassFiled* GetFiled(const std::string& className, const std::string& filedName);
    
private:
    std::map<std::string, std::vector<ClassFiled*>> mClassFileds; // className -> classFileds
};

// ClassFactory.cpp
void ClassFactory::RegisterClassFiled(const std::string& className, ClassFiled* filed)
{
    mClassFileds[className].push_back(filed);
}

size_t ClassFactory::GetFiledCount(const std::string& className)
{
    return mClassFileds[className].size();
}

ClassFiled* ClassFactory::GetFiled(const std::string& className, size_t pos)
{
    size_t len = mClassFileds[className].size();
    if (pos < 0 || len <= pos)
    {
        return nullptr;
    }
    return mClassFileds[className][pos];
}

ClassFiled* ClassFactory::GetFiled(const std::string& className, const std::string& filedName)
{
    for (auto filed : mClassFileds[className])
    {
        if (filed->Name()._Equal(filedName))
        {
            return filed;
        }
    }
    return nullptr;
}

扩展ClassRegister

class ClassRegister
{
public:
    ClassRegister(const std::string& className, const std::string& filedName, const std::string& filedType, size_t offset)
    {
        ClassFactory* factory = Singleton<ClassFactory>::Instance();
        factory->RegisterClassFiled(className, new ClassFiled(filedName, filedType, offset));
    }
};

// 用于注册类参数的宏
#define REGISTER_CLASS_PARAMETER(className, filedName, type)    \
    ClassRegister classRegister##className##filedName(#className, #filedName, #type, offsetof(className, filedName))

扩展Object

// Object.h
class Object
{
public:
    template<typename T>
    void Set(const std::string& filedName, const T& value);
    
    template<typename T>
    void Get(const std::string& filedName, T& value);
};

// ClassFactory.h
template <typename T>
void Object::Set(const std::string& filedName, const T& value)
{
    ClassFactory* factory = Singleton<ClassFactory>::Instance();
    ClassFiled* filed = factory->GetFiled(mClassName, filedName);
    *reinterpret_cast<T*>((size_t)this + filed->Offset()) = value;
}

template <typename T>
void Object::Get(const std::string& filedName, T& value)
{
    ClassFactory* factory = Singleton<ClassFactory>::Instance();
    ClassFiled* filed = factory->GetFiled(mClassName, filedName);
    value = *reinterpret_cast<T*>((size_t)this + filed->Offset());
}

验证

class A :public Object
{
public:
    int ANum = 3;
    std::string AString = "this is a a test";
    std::vector<int> mVector;
};

REGISTER_CLASS(A);
REGISTER_CLASS_PARAMETER(A, ANum, int);
REGISTER_CLASS_PARAMETER(A, AString, string);
REGISTER_CLASS_PARAMETER(A, mVector, vector<int>);

class B : public Object
{
public:

    int BNum = 2;
    std::string BString = "this is a b test";
};

REGISTER_CLASS(B);
REGISTER_CLASS_PARAMETER(B, BNum, int);
REGISTER_CLASS_PARAMETER(B, BString, string);


int main(int argc, char* argv[])
{
    ClassFactory * factory = Singleton<ClassFactory>::Instance();
    Object* o1 = factory->CreateClass("A");
    o1->showClassName();
    size_t num = 0;
    string name = "";
    vector<int> vec;
    o1->Get("ANum", num);
    o1->Get("AString", name);
    o1->Get("mVector", vec);
    cout << num << "\t" << name << endl;
    for (auto value : vec)
    {
        cout << value << endl;
    }
    o1->Set("ANum", 17);
    o1->Set("AString", string("kk"));
    o1->Set("mVector", vector<int>(3, 6));
    o1->Get("ANum", num);
    o1->Get("AString", name);
    o1->Get("mVector", vec);
    cout << num << "\t" << name << endl;
    for (auto value : vec)
    {
        cout << value << endl;
    }

    
    Object* o2 = factory->CreateClass("B");
    o2->Get("BNum", num);
    o2->Get("BString", name);
    o2->showClassName();
    cout << num << "\t" << name << endl;
}

执行结果如下,说明已经可以通过反射来控制参数

A
3       this is a a test
17      kk
6
6
6
B
2       this is a b test
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值