1

我一直在研究 Curiously Recurring Template Pattern 以确定如何使用它来实现桥接设计模式。

我的问题是将 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); 
    }
};
4

2 回答 2

3

当你LoadDriverClient::Init函数中调用时,ValueTemplateType模板参数是std::string*,即一个指针。桥实现类BridgeImplementation1BridgeImplementation2具有带指针的功能。所以当编译器试图找到一个匹配的LoadDriver函数时,它不会考虑接受非指针参数的函数,只考虑接受指针参数的函数。

您应该更改LoadDriver函数BridgeImplementation1BridgeImplementation2采用指针参数。

于 2013-02-06T07:13:22.787 回答
3

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

如果您想在您的情况下完全避免虚拟调度,您不能完全将客户端与 Bridge 分离,您需要在 Bridge 上模板 Client 与仅在 Derived 上模板相比并没有真正给您带来任何优势。

这是做你想做的事的机会。它假设您通过 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){ /*...*/ }
};
于 2013-02-06T07:21:41.850 回答