Я работаю над структурой плагинов, которая поддерживает несколько вариантов базового класса плагинов 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
, он не может определить тип и вести себя по-разному в соответствии с параметром шаблона. Я не могу понять, как избежать объявления ::Enable()
и ::Disable()
закрытыми членами IPlugin
, но это мгновенно означает, что каждый раздел приложения теперь должен знать о классе CPluginMgr
, поскольку он объявлен как друг в шапке. Появляется круговая зависимость ада. Я вижу другой вариант, объявляю функции включения / выключения частными членами 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
. Если у кого-то есть лучшее предложение, пожалуйста, поделитесь им!