c++中的反射机制与插件式编程

反射机制大致是通过类名称字符串生成该类的实例,以及通过其方法名称字符串调用该方法。在c++中貌似不支持反射机制,可以参考这篇博客C++反射机制的实现 | 繁夜通过一些“迂回”的方式实现c++的反射机制。

  • 反射机制有什么用?——反射机制可以在运行时确定要生成的类或要调用的函数。
    比如需要做一个插件式的程序,主程序提供界面,各个新添加功能可以作为插件添加到主程序中而不需要重新编译整个主程序。要实现这一点,可以把插件做成dll文件,放在主程序下,在运行时调用;这些插件应该继承自统一的接口,这个接口在主程序中定义,这样主程序可以知道这些“新功能”的一致的使用方式。现在唯一的问题是,在主程序中需要生成插件中定义的类,需要使用其构造函数,但是主程序并不知道这些插件中类的名称及其构造函数的名称,因为这些插件可能是未来由用户自己开发的,不可能在主程序编译的时候得知。只能在主程序运行时获知当前工作目录下有什么dll插件文件,如果这些文件命名遵循某种规范的话(比如插件的名称均为类名_plugin.dll)这样可能可以推知该插件中主要类的名称,于是问题归结成了使用名称字符串生成类。
  • 其主要的思路是:
  1. 定义一个工厂(Factory)类,这个类中的函数用于管理类的反射信息以及创建具体实例,该类维护一个全局的反射信息映射表,该表是一个map类对象,可以通过未来的类名字符串检索未来的类的信息(信息可能包括类名、构造函数指针及其他信息);该工厂类创建实例时根据给出的类名字符串索引其构造函数,使用其构造函数构造其自身
  2. 在以后自定义的类,如果希望其实现反射功能,应该在该类中维护一个ClassInfo类的静态成员变量来保存自身信息,并将该信息注册到反射信息映射表中(相当于把自己登记一下,以后使用者可以找到自己的构造函数)
  • 我略微改动了一点点繁夜的那篇博客示例,如下:
//reflex.h
#ifndef REFLEX_H
#define REFLEX_H
#include <string>
#include <map>

#define CONSTRUCTOR(class_name)\
public:\
static ReflexBase* CreateObject()\
{\
	return new class_name;\
}\
protected:\
static ClassInfo m_classInfo;

#define REGISTER_REFLEX(class_name)\
ClassInfo class_name::m_classInfo(#class_name,class_name::CreateObject);

class ClassInfo;
class ReflexBase;
static std::map<std::string, ClassInfo*> *m_classInfoMap;

class Factory 
{
public:
	Factory() {}
	virtual ~Factory() {}
	static bool Register(ClassInfo *pCInfo);
	static ReflexBase* CreateObject(std::string className);
	static ClassInfo* GetClassInfo(std::string className);
};
typedef ReflexBase* (*objConstructorFun)();
class ClassInfo
{
public:
	ClassInfo(const std::string className, objConstructorFun classConstructor) :
		m_className(className), m_objConstructor(classConstructor)
	{
		Factory::Register(this);
	}
	virtual ~ClassInfo() {}
	ReflexBase* CreateObject()const { return m_objConstructor ? (*m_objConstructor)() : NULL; }
	bool IsDynamic()const { return NULL != m_objConstructor; }
	const std::string GetClassName()const { return this->m_className; }
	objConstructorFun GetConstructor()const { return this->m_objConstructor; }
private:
	std::string m_className;
	objConstructorFun m_objConstructor;
};

class ReflexBase
{
public:
	ReflexBase() {}
	virtual ~ReflexBase() {}
};
#endif

其源文件:

//reflex.cpp
#include "stdafx.h"
#include "reflex.h"
#include <map>


bool Factory::Register(ClassInfo * pCInfo)
{
	if (!m_classInfoMap) {
		m_classInfoMap = new std::map<std::string, ClassInfo*>();
	}
	if (!pCInfo) {
		return false;
	}
	if (m_classInfoMap->end() == m_classInfoMap->find(pCInfo->GetClassName())) {
		m_classInfoMap->insert(std::map<std::string, ClassInfo*>::value_type(pCInfo->GetClassName(), pCInfo));
	}
	return true;
}

ReflexBase * Factory::CreateObject(std::string className)
{
	std::map<std::string, ClassInfo*>::const_iterator c_iter = m_classInfoMap->find(className);
	if (m_classInfoMap->end() != c_iter) {
		return c_iter->second->CreateObject();
	}
	return NULL;
}

ClassInfo * Factory::GetClassInfo(std::string className)
{
	std::map<std::string, ClassInfo*>::const_iterator c_iter = m_classInfoMap->find(className);
	if (m_classInfoMap->end() != c_iter) {
		return c_iter->second;
	}
	return NULL;
}

以上,定义了Factory类用于管理反射机制,而使用ReflexBase类仅作为一个反射机制的基类,没有什么功能。在使用时如果需要让自己的类拥有以上的(简化的)反射机制,可以让自己的类继承自ReflexBase类(或者它的子类)。对于上面提到的插件开发的实例,如果使用ReflexBase作为插件的基类未免太简单,因为我们可能需要未来的插件符合具体的某种接口,所以有两种思路:

  • 自定义的插件继承自插件接口与ReflexBase类。但是这里用到多继承,不推荐。
  • 插件接口类继承自ReflexBase类,然后自定义的插件继承自插件接口。实测可行。
    示例代码如下:
//test_reflex.cpp
// TestReflec.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
#include <string>
#include "reflex.h"
class Plugin:public ReflexBase
{
public:
	Plugin();
	virtual ~Plugin();
	virtual void func();//将来插件要实现的功能
};
class PluginA :public Plugin
{
public:
	PluginA();
	~PluginA();
	//使用CONSTRUCTOR宏给该插件构造工厂函数
	CONSTRUCTOR(PluginA)
	void func();
};
//注册该插件类的信息
REGISTER_REFLEX(PluginA)

class PluginB :public Plugin
{
public:
	PluginB();
	~PluginB();
	CONSTRUCTOR(PluginB)
	void func();
};
REGISTER_REFLEX(PluginB)

int main()
{
	Plugin* test = (Plugin*)(Factory::CreateObject("PluginA"));
	std::cout << "test class name=" << Factory::GetClassInfo("PluginA")->GetClassName() << ",constructor add[" << Factory::GetClassInfo("PluginA")->GetConstructor() << std::endl;
	test->func();
	Plugin* test1 = (Plugin*)(Factory::CreateObject("PluginB"));
	std::cout << "test1 class name=" << Factory::GetClassInfo("PluginB")->GetClassName() << ",constructor add[" << Factory::GetClassInfo("PluginB")->GetConstructor() << std::endl;
	test1->func();
	delete test;
	delete test1;
	system("pause");
	return 0;
}

PluginA::PluginA()
{
	std::cout << "ADDR:[" << std::hex << (long)this << "].The Object Name is \"PluginA\" constructed!" << std::endl;
}

PluginA::~PluginA()
{
	std::cout << "ADDR:[" << std::hex << (long)this << "].The Object Name is \"PluginA\" destroyed!" << std::endl;
}

void PluginA::func()
{
	std::cout << "func in PluginA class exec..." << std::endl;
}

PluginB::PluginB()
{
	std::cout << "ADDR:[" << std::hex << (long)this << "].The Object Name is \"PluginB\" constructed!" << std::endl;
}

PluginB::~PluginB()
{
	std::cout << "ADDR:[" << std::hex << (long)this << "].The Object Name is \"PluginB\" destroyed!" << std::endl;
}

void PluginB::func()
{
	std::cout << "func in PluginB class exec..." << std::endl;
}

Plugin::Plugin()
{
	std::cout << "ADDR:[" << std::hex << (long)this << "].The Object Name is \"Plugin\" constructed!" << std::endl;
}

Plugin::~Plugin()
{
	std::cout << "ADDR:[" << std::hex << (long)this << "].The Object Name is \"Plugin\" destroyed!" << std::endl;
}

void Plugin::func()
{
	std::cout << "func in Plugin class exec..." << std::endl;
}

运行结果:
在这里插入图片描述
这里如果使用多继承的方式,即如果:

class Plugin//这里不继承ReflexBase
{
	...
}
class PluginA:pubic Plugin,public ReflexBase
{
	...
}

的话,会出现访问冲突,因为在主函数中是这么构造Plugin对象的:

Plugin* test = (Plugin*)(Factory::CreateObject("PluginA"));

实际上这里使用Factory::Create构造的是ReflexBase*类型,需要先转成子类指针再转换成Plugin*,因为ReflexBasePlugin没有什么继承关系,两个不相关的类型是没法直接转的,应该如下:

Plugin* test = (Plugin*)(PluginA*)(Factory::CreateObject("PluginA"));

但是这相当于在主程序编译的时候就知道以后开发的插件叫啥了,那干脆也不需要反射了,直接:

Plugin *test=new PluginA();

这不符合实际需求,多继承的方式在这个例子中是不恰当的。
还有一种考虑是让Plugin继承自ReflexBasePluginA继承自PluginReflexBase,这太蠢了,别这么做。

  • 7
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值