2009-08-10 3 views
1

Я работаю над фреймворком плагина, который поддерживает несколько вариантов базового класса плагина 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 шаблона. Если у кого-то есть лучшее предложение, поделитесь им!

+0

Почему шаблон «CPlugin» templated? вы должны знать, что класс может быть не шаблоном, но иметь шаблонную функцию-член (в данном случае клон). –

+0

Возможно, я что-то делаю, но не могу просто сделать: 'plugin-> Enable();' если плагин имеет тип 'PluginPtr' ?. Это своего рода точка интерфейса ... –

+0

Я не хочу, чтобы какой-либо класс, отличный от CPluginMgr, мог отключить/включить плагины. – AlasdairC

ответ

2

Вы можете легко написать:

class CPluginMgr; 

class IPlugIn .. 
{ 
    friend CPluginMgr; 
    ... 
}; 

Только предопределение нужно для друга.

+0

Я могу ' Я считаю, что это так просто, но это так :) Спасибо Кристофер! – AlasdairC

+0

Не забудьте принять решение Кристофера ... – neuro

+0

err Я сделал, извините, что – AlasdairC

0

Я думаю, что у вас проблемы с попыткой вернуть метод shared_ptr в клоне. Почему бы вам не использовать Ковариантные типы возврата? То, что вы делаете, является распространенной идиомой под названием Virtual Constructor.

class IPlugin 
{ 
public: 
    virtual IPlugin* clone() = 0; 
    // ... 
} 

class CPluginMgr; 

class CPlugin : public IPlugin 
{ 
public: 
    virtual CPlugin* clone() = 0; 
    friend CPluginMgr; // as @Christopher pointed out 
    void Enable(bool enable) { m_disabled = !enable; } 
    // ... 
} 

class CAudioDSP : public CPlugin 
{ 
public: 
    virtual CAudioDSP* clone(); 
    // ... 
} 

CAudioDSP* CAudioDSP::clone() 
{ 
    return new CAudioDSP(*this); // assume copy constructors are properly implemented 
} 

Возвращение shared_ptr может привести вас сделать ошибки (как раннее разрушение temparary объектов), и я думаю, как правило, не является хорошей идеей.

Смежные вопросы