如何使用奇怪的重复模板模式的桥模式?

时间:2013-02-06 06:55:57

标签: c++ c++11 design-patterns crtp bridge

我一直在研究奇怪的重复模板模式,以确定如何使用它来实现桥设计模式。

我的问题是将IBridgeConnector :: GetBridgeImpl方法连接到Bridge :: GetBridgeImpl方法,因为覆盖方法实际上是模板化的。

由于虚拟调度在这种情况下不起作用,将这些方法指向对方的最佳方法是什么?功能代表?对此有更好的模式吗?

应该怎么做?

感谢您的帮助!

我可以在没有shared_ptrs和OpenGL和DirectX调用的情况下实现最佳代码简化。 :)希望这对未来的人有用!

#include <string>
/********************************************************************/
class BridgePart
{
public:
    BridgePart * OtherPart;
};

/********************************************************************/
// Connects a BridgeSource and a BridgeImplementation
class BridgeConnector
{
public:
    static BridgeConnector * implementor;

    // Need a way, (Function Delegates?) to point this method
    // This method will loop until stack overflow.
    template <typename ValueTemplateType>
    BridgePart * GetBridgeImpl(ValueTemplateType * source)
    {
        return implementor->GetBridgeImpl<ValueTemplateType>(source);
    }
};
BridgeConnector * BridgeConnector::implementor = nullptr;

/********************************************************************/
// Where the Magic is At, (CRTP)
template <typename BridgeImplementationTemplateType>
class Bridge : public BridgeConnector
{
public:
    template <typename ValueTemplateType>
    IBridgePart * GetBridgeImpl(IBridgePart * source)
    {
        // NOTE:  This method never gets called.
        // CRTP Magic Here to Semi-Specify Pure Virtual Methods
        return static_cast<BridgeImplementationTemplateType>(this)
            ->GetBridgeImpl( (ValueTemplateType) source);
    }
};

/********************************************************************/
class BridgeImplementation1 : 
    public Bridge<BridgeImplementation1>,
    public BridgePart
{
public:
    class CustomImpl : public BridgePart
    {
    public:
        template <typename SourceTemplateType>
        BridgePart(SourceTemplateType source){}
            /* Does proprietary stuff. */
    };

    template <typename ValueTemplateType>
    BridgePart * GetBridgeImpl(ValueTemplateType & source)
    {
        return new CustomImpl<ValueTemplateType>(source);       
    }
    // Constructor
    BridgeImplementation1()
    {
    }
};

/********************************************************************/
class BridgeSource1 : public BridgePart {};
class BridgeSource2 : public BridgePart {};
class Client
{
    BridgeSource1 source1;
    BridgeSource2 source2;
    BridgeConnector * connector;
    bool usingImpl1;

    Client()
    {
        usingImpl1 = true; // from config file.
        connector = new BridgeConnector();
        connector->implementor = usingImpl1 
            ? (BridgeConnector *) new BridgeImplementation1()
            : nullptr; // (BridgeConnector *) new BridgeImplementation2();  
        // removed to shorten code.
    }

    void Init()
    {
        source1.OtherPart = connector->GetBridgeImpl<BridgeSource1>(& source1);
        source2.OtherPart = connector->GetBridgeImpl<BridgeSource2>(& source2); 
    }
};

2 个答案:

答案 0 :(得分:3)

当您在LoadDriver函数中调用Client::Init时,ValueTemplateType模板参数为std::string*,即指针。桥实现类BridgeImplementation1BridgeImplementation2具有获取指针的函数。因此,当编译器试图找到匹配的LoadDriver函数时,它不会考虑采用非指针参数的函数,只考虑采用指针参数的函数。

您应该更改LoadDriverBridgeImplementation1中的BridgeImplementation2函数以获取指针参数。

答案 1 :(得分:3)

我认为你对CRTP有点误解。它不是虚拟调度的插件替代品。在您的情况下,IBridge没有虚拟调度,因此调用IBridge-&gt; LoadDriver将始终为您提供默认的基类实现,而不管底层的派生类。如果需要通用接口,则需要某种虚拟分派。 CRTP只是在不需要的情况下避免虚拟分派的一种方法,例如当基类成员函数调用其他虚函数时。

如果你想在你的情况下完全避免虚拟调度,你不能完全将客户端与Bridge分离,你需要在Bridge上模拟Client,这实际上并没有给你带来任何优于衍生的模板的优势。 / p>

这是拍摄你想做的事情。它假设您通过IBridge传递一些通用指针,Bridge使用CRTP解释并传递给BridgeImpl。显然,你已经放弃了对这一论点的所有类型安全的希望。

class IBridge {
    virtual void LoadDriver(void *) = 0;
};

template <typename Impl>
class Bridge : public IBridge {
    void LoadDriver(void * v) override {
        static_cast<Impl*>(this)->LoadDriverImpl(*static_cast<Impl::arg_type *>(v));
    }
};

class BridgeImpl : public Bridge<BridgeImpl> {
    typedef std::string arg_type;
    void LoadDriverImpl(const std::string & s){ /*...*/ }
};