2009-08-10 66 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它無法確定類型和行爲不同,根據模板參數。我看不到如何避免聲明::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模板的許多多個變種。如果有人有更好的建議,請分享!

+0

爲什麼'CPlugin'是模板化的?你應該知道一個類可以是一個非模板,但有一個模板化的成員函數(在本例中爲克隆)。 – 2009-08-10 15:48:14

+0

也許我正在做點什麼,但是你不能這樣做:'plugin-> Enable();'如果plugin的類型是'PluginPtr' ?.這是接口的點... – 2009-08-10 15:50:44

+0

我不希望除CPluginMgr以外的任何其他類能夠禁用/啓用插件 – AlasdairC 2009-08-10 16:27:00

回答

2

您可以輕鬆地寫:是需要的朋友

class CPluginMgr; 

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

只有預定義。

+0

我可以'相信它是如此簡單,但它是:) 謝謝克里斯託弗! – AlasdairC 2009-08-10 16:29:08

+0

不要忘記接受克里斯托弗的解決方案... – neuro 2009-08-10 17:36:04

+0

犯錯了,對不起 – AlasdairC 2009-08-16 20:14:36

0

我覺得你會遇到麻煩,試圖在克隆方法中返回一個shared_ptr。你爲什麼不利用covariant返回類型?你在做什麼是一種常見的成語,叫做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對象的早期破壞),我認爲通常不是一個好主意。