跟我学c++高级篇——类反射

240 篇文章 100 订阅

一、类反射

在分析了简单类和结构体后,可以进一步的分析普通类的反射了,对一个类进行反射,一般有下面几种情况:
1、通过类名进行对象的创建和匹配
2、对类成员变量的反射
3、对类成员函数的反射
4、可以处理类的继承等关系
这里只对基础的部分进行处理,包括继承等复杂的应用暂时不关心。

二、实现机制

类反射机制仍然重点是以分析如何获得类类型、成员函数和变量和进行展开,相关的复杂的应用会在后面进行继续专门的分析。类反射的实现有几种方式:
1、使用基础的STL的相关元库
这种机制一般只能进行判断而无法进行直接的类对象和成员的调用
2、使用宏和模板(含元编程)实现
这种机制实现较为复杂,但可能应用起来比较全面
3、使用开源的框架或库
这种机制其实就是别人封装好的反射调用,但风格可能千奇百异

这里不在严格的以动态或者静态反射区分,而以实现的机制来做分析的方向,至于这种实现属于哪种或者是否是二者结合,自行分辨即可。

三、实现

在前面已经实现过类似于POD类型的成员反射,所以这里先略过这些;而利用Traits STL库来实现对类及成员进行判断的回头也拿出一章来专门分析,其中一些个别的用法也已经在展开具体分析了。
所以,本文主要对反射生成对象和普通成员函数进行反射调用。

四、例程分析

下面看一个初步的实现:
1、基础实例对象管理类

#pragma once
#include <string>
#include <iostream>

class Ins
{
public:
    void SetName(const std::string& cName)
    {
        className = cName;
    }

    void getName() const
    {
        std::cout << className << std::endl;
    }
public:
    void GetFunc(const std::string& FuncName);
public:
    std::string className;
};
typedef Ins* (*createIns)(void);


class ClassFunc
{
public:
    ClassFunc(const std::string& name, uint64_t Func) : funcName(name), pFunc(Func) {}

    const std::string& Name() { return funcName; }
    const uint64_t Func() { return pFunc; }

private:
    std::string funcName;
    uint64_t pFunc;
};
#include "ins.h"
#include <functional>
#include "singleton.h"
#include "factory.h"

void Ins::GetFunc(const std::string& funcName)
{
    ClassFunc* ClassFunc = Singleton<Factory>::Instance()->GetMemFunc(className, funcName);

    if (ClassFunc == nullptr) {
        std::cerr << "get func err!" << std::endl;
        return;
    }

    typedef std::function<void(Ins*)> CFunc;
    (*reinterpret_cast<CFunc*>(ClassFunc->Func()))(this);
}

2、一个单例类

#pragma once
#include <mutex>

template<typename T>
class Singleton
{
public:
    Singleton() = default;
    ~Singleton() = default;
    Singleton(const Singleton& other) = delete;
    Singleton& operator=(const Singleton& other) = delete;
public:
    static T* Instance()
    {
        static T* t = new T();
        return t;
    }
};

注意:c++0x以后安全.

3、注册工厂

#pragma once
#include <map>
#include <string>
#include <vector>
#include "singleton.h"
#include "ins.h"

class Factory
{
public:
    Factory() = default;
    virtual ~Factory() = default;
public:
    void ClassReg(const std::string& className, createIns func);
    Ins* GetObject(const std::string& className);
    void RegMemFunc(const std::string& className, ClassFunc* func);
    ClassFunc* GetMemFunc(const std::string& className, const std::string& funcName);
private:
    std::map<std::string, createIns> mapClassName;
    std::map<std::string, std::vector<ClassFunc*>> mapClassFunc;
};
#include "factory.h"
void Factory::ClassReg(const std::string& className, createIns func)
{
    this->mapClassName.emplace(className,func);
}

Ins* Factory::GetObject(const std::string& className)
{
    if (this->mapClassName.count(className) > 0) {
        return this->mapClassName[className]();
    }

    return nullptr;
}
void Factory::RegMemFunc(const std::string& className, ClassFunc* func)
{
    mapClassFunc[className].emplace_back(func);
}


ClassFunc* Factory::GetMemFunc(const std::string& className, const std::string& funcName)
{
    if (this->mapClassFunc.count(className) > 0)
    {
        for (auto func : mapClassFunc[className])
        {
            if (func->Name()==funcName)
            {
                return func;
            }
        }
    }


    return nullptr;
}

4、注册和测试类


#include <iostream>
#include <mutex>
#include <map>
#include <vector>
#include <functional>

#include "singleton.h"
#include "factory.h"


class RegClass
{
public:
    RegClass(const std::string& className, createIns func)
    {
        Singleton<Factory>::Instance()->ClassReg(className, func);
    }
public:
    RegClass(const std::string& className, const std::string& funcName, uint64_t func)
    {
        auto factory = Singleton<Factory>::Instance();
        factory->RegMemFunc(className, new ClassFunc(funcName, func));
    }
};

#define REG_CLASS(class_name)   \
    Ins* createIns##class_name()    \
    {                                  \
        Ins* o = new class_name();   \
        o->SetName(#class_name);    \
        return o;                    \
    }                                 \
    RegClass RegClass##class_name(#class_name, createIns##class_name)

#define REG_CLASS_FUNC(class_name, func_name)  \
    std::function<void(class_name*)> class_name##func_name = &class_name::func_name; \
    RegClass RegClass##class_name##func_name(#class_name, #func_name, (uint64_t)&(class_name##func_name))

class Ex0 :public Ins
{
};

REG_CLASS(Ex0);

class Ex1 : public Ins
{
};

REG_CLASS(Ex1);
void  testClassRegister()
{
    auto factory = Singleton<Factory>::Instance();
    auto i0 = factory->GetObject("Ex0");
    i0->getName();
    auto i1 = factory->GetObject("Ex1");
    i1->getName();

}


class Ex2 :public Ins
{
public:
    void Test()
    {
        std::cout << "Ex2 Test!" << std::endl;
    }
};
REG_CLASS(Ex2);
REG_CLASS_FUNC(Ex2, Test);


class Ex3 : public Ins
{
public:
    void Test()
    {
        std::cout << "Ex3 Test!" << std::endl;
    }
};
REG_CLASS(Ex3);
REG_CLASS_FUNC(Ex3, Test);


void testFunc()
{
    auto factory = Singleton<Factory>::Instance();
    Ins* i2 = factory->GetObject("Ex2");
    Ins* i3 = factory->GetObject("Ex3");
    i2->GetFunc("Test");
    i3->GetFunc("Test");
}

int main()
{
    testClassRegister();
    testFunc();

    return 0;
}


对类反射生成对象采用的是注册一个创建实例对象的函数指针;对成员函数的处理则是将其地址保存到Map中,在需要时进行调用。有一个比较难理解的是使用整形来替代类成员指针,这个没有什么,毕竟指针就是一个地址,地址就是一个整形的变量类型指向的位置。
上面的代码很清晰就不进一步的解释了,它主要是借鉴了QT中的类反射实现方式。
这个代码改进的究竟还相当大,但这里只是为了展示反射实现的过程,所以力求简单明了。比如注册类生成对象的函数可以使用模板函数,这样更灵活。以后有时间会进一步的进行优化。

五、总结

反射对c++是不是一种鸡肋,这个还真不好说。不过有一句话可以引入进来,“发展是硬道理”,只要是不断的发展,就会有机会。而停滞不前的空谈理论,一定是没有前途的。至于以后反射在c++后续标准里会成为什么样子,大家拭目以待即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值