Я работаю над фреймворком плагина, который поддерживает несколько вариантов базового класса плагина CPlugin : IPlugin
. Я использую boost::shared_ptr<IPlugin>
для всех ссылок на плагины, за исключением случаев, когда подсистема нуждается в конкретном интерфейсе типа плагина. Мне также нужна способность клонировать плагин в другой отдельный объект. Это должно вернуть PluginPtr
. Вот почему CPlugin
- это шаблон, а не прямой класс. CPlugin::Clone()
- где используется шаблонный параметр. Ниже приведены определения классов, которые я использую:интерфейсы для шаблонных классов
IPlugin.h
#include "PluginMgr.h"
class IPlugin;
typedef boost::shared_ptr<IPlugin> PluginPtr;
class IPlugin
{
public:
virtual PluginPtr Clone() =0;
virtual TYPE Type() const =0;
virtual CStdString Uuid() const =0;
virtual CStdString Parent() const =0;
virtual CStdString Name() const =0;
virtual bool Disabled() const =0;
private:
friend class CPluginMgr;
virtual void Enable() =0;
virtual void Disable() =0;
};
CPlugin.h
#include "IPlugin.h"
template<typename Derived>
class CPlugin : public IPlugin
{
public:
CPlugin(const PluginProps &props);
CPlugin(const CPlugin&);
virtual ~CPlugin();
PluginPtr Clone();
TYPE Type() const { return m_type; }
CStdString Uuid() const { return m_uuid; }
CStdString Parent() const { return m_guid_parent; }
CStdString Name() const { return m_strName; }
bool Disabled() const { return m_disabled; }
private:
void Enable() { m_disabled = false; }
void Disable() { m_disabled = true; }
TYPE m_type;
CStdString m_uuid;
CStdString m_uuid_parent;
bool m_disabled;
};
template<typename Derived>
PluginPtr CPlugin<Derived>::Clone()
{
PluginPtr plugin(new Derived(dynamic_cast<Derived&>(*this)));
return plugin;
}
Пример конкретный класс CAudioDSP.h
#include "Plugin.h"
class CAudioDSP : CPlugin<CAudioDSP>
{
CAudioDSP(const PluginProps &props);
bool DoSomethingTypeSpecific();
<..snip..>
};
Моя проблема (наконец) заключается в том, что CPluginMgr
нуждается в обновлении m_disabled
конкретного класса, однако, поскольку он передан PluginPtr
, у него нет способа определить тип и вести себя по-разному в соответствии с шаблоном paramater. Я не вижу, как избежать объявления ::Enable()
и ::Disable()
в качестве частных членов IPlugin
, но это мгновенно означает, что каждый раздел приложения теперь должен знать класс CPluginMgr
, так как он объявлен как друг в заголовке. Наступает круговая зависимость. Я вижу еще один вариант: объявляйте функции Enable/Disable как частные члены CPlugin и вместо этого используйте boost::dynamic_pointer_cast<CVariantName>
.
void CPluginMgr::EnablePlugin(PluginPtr plugin)
{
if(plugin->Type == PLUGIN_DSPAUDIO)
{
boost::shared_ptr<CAudioDSP> dsp = boost::dynamic_pointer_cast<CAudioDSP>(plugin);
dsp->Enable();
}
}
Это, однако, приводит к большому количеству повторяющегося кода со многими несколькими вариантами базовой CPlugin
шаблона. Если у кого-то есть лучшее предложение, поделитесь им!
Почему шаблон «CPlugin» templated? вы должны знать, что класс может быть не шаблоном, но иметь шаблонную функцию-член (в данном случае клон). –
Возможно, я что-то делаю, но не могу просто сделать: 'plugin-> Enable();' если плагин имеет тип 'PluginPtr' ?. Это своего рода точка интерфейса ... –
Я не хочу, чтобы какой-либо класс, отличный от CPluginMgr, мог отключить/включить плагины. – AlasdairC