2009-08-10 67 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对象的早期破坏),我认为通常不是一个好主意。