如何使用TR1实现观察者模式模板基类

C++ How to implement observer pattern template base class using TR1

本文关键字:基类 观察者模式 实现 何使用 TR1      更新时间:2023-10-16

我想实现一个类"MyClass"作为一个基础的可观察类。例如:

class Observed : public MyClass<Observed>{
public: void DoWork() {.... MyClass<Observed>::NotifyObservers();}
};
class AnyObserver {public: HandleObserved(Observed& ob){...}};
AnyObserver any;
Observed observed;
observed.AddObserver(&any, &AnyObserver::HandleObserved);
observed.DoWork();.....

以下是我到目前为止的实现。我相信这将工作得很好,除了我进入编译问题。

template <typename T>
class MyClass
{
typedef std::tr1::function<void( T& )> CallbackFunction;
std::list< CallbackFunction > m_observers;
template<class S>
struct TypeHelper
{
            //I. Compilation error is here: Unexpected "...
    typedef void (typename S::*Signature)(T&);
};
public:
template<class M>
void AddObserver(M& observer, TypeHelper<M>::Signature callback) 
{
    CallbackFunction bound = std::tr1::bind(callback, observer, tr1::placeholders::_1);
    m_observers.push_back(bound);       
}
protected:
void NotifyObservers() 
{  
    std::list< CallbackFunction >::iterator iter = m_observers.begin();
    for (; iter != m_observers.end(); ++iter )
    {
        // II. is static_cast the right way to go?
        (*iter)(static_cast<T&>(*this));
    }
}
};

对于问题1和问题2(在评论中)的任何帮助都将不胜感激。

I:我定义了struct TypeHelper,试图获得所需的成员指针类型。当类类型为模板化的m时,无法找到其他方法来完成此操作。

II:我如何强制MyClass中的模板类型匹配class Observed : public MyClass<Observed>中继承的类型。最好的方法是什么?

这是一个可能的解决方案,对原始工作进行一些更改(使用禁用扩展的VC2010):

template <typename T>
class MyClass
{
private:
    typedef std::function<void( T& )> CallbackFunction;
    std::list< CallbackFunction > m_observers;
public:
    virtual ~MyClass() {}
    template<class M>
    void AddObserver(M& observer, void typename (M::*callback)(T&))
    {
        CallbackFunction bound =
            std::bind(callback, observer, std::placeholders::_1);
        m_observers.push_back(bound);       
    }
protected:
    void NotifyObservers() 
    {  
        std::list< CallbackFunction >::iterator iter = m_observers.begin();
        for (; iter != m_observers.end(); ++iter )
        {
            (*iter)(static_cast<T&>(*this));
        }
    }
};
class Observed : public MyClass<Observed>
{
public:
    void DoWork()
    {
        MyClass<Observed>::NotifyObservers();
    }
};
class AnyObserver
{
public:
    void HandleObserved(Observed&)
    {
        std::cout << "Observedn";
    }
};
int main(int /*a_argc*/, char** /*a_argv*/)
{
    AnyObserver any;
    Observed observed;
    observed.AddObserver(any, &AnyObserver::HandleObserved);
    observed.DoWork();
    return 0;
}

您可能需要在适当的地方重新添加tr1名称空间。主要的变化是删除了TypeHelper模板类。

对于static_cast的使用,如果你确定你知道对象的类型是可以的。查看static_castdynamic_cast的详细答案。

编辑:

如何强制MyClass中的模板类型与class> Observed: public MyClass中继承的类型匹配?最好的方法是什么?

一个可能的运行时解决方案是使用dynamic_cast,因为如果强制转换无效,它将返回0:

    void NotifyObservers() 
    {  
        std::list< CallbackFunction >::iterator iter = m_observers.begin();
        for (; iter != m_observers.end(); ++iter )
        {
            T* t = dynamic_cast<T*>(this);
            if (0 != t)
            {
                (*iter)(*t);
            }
            else
            {
                std::cerr << "Failed to castn";
            }
        }
    }
如果定义了以下类,

dynamic_cast将返回0:

class XObserved : public MyClass<Observed>
{
public:
    void DoWork()
    {
        MyClass<Observed>::NotifyObservers();
    }
};

如何在MyClass中强制模板类型与类型匹配继承为观察类:公共MyClass。是什么最好的方法是什么?

这也可以在编译时完成。由Observer处理程序执行检查可能是最有意义的。在MyClass中添加一个处理程序可以检查的类型,比如DerivedType:

template <typename TT>
class MyClass
{
public: 
    typedef TT DerivedType;
};
template <typename AA, typename BB>
struct SameType;
template <typename AA>
struct SameType<AA, AA> {};
class AnyObserver
{
public:
    template <typename VV>
    void HandleObserved(VV&)
    {
        std::cout << "Observedn";
        SameType<VV, VV::DerivedType>();
    }
};

如果VV不是从MyClass派生的,那么HandleObserved()将编译失败,因为SameType只有在VV有一个类型DerivedType作为成员,并且VV和VV::DerivedType是相同类型时才会成功,这只有在VV派生自MyClass时才会发生。

class Derived: public MyClass<Derived>
{
};
class NotDerived
{
};
class Foo 
{
};
class BadDerived1: public MyClass<Foo>
{
};
class BadDerived2: public MyClass<Derived>
{
};

和一个显示这些可观察对象代码的测试,导致编译时错误:

void test()
{
    Derived foo;       // ok
    NotDerived bad1;   // ok so far
    BadDerived1 bar1;  // ok so far
    BadDerived2 bar2;  // ok so far
    AnyObserver obs;
    obs.HandleObserved(foo);    // ok
    //obs.HandleObserved(bad1); // BANG! at compile time
    //obs.HandleObserved(bar1); // BANG! at compile time
    //obs.HandleObserved(bar2); // BANG! at compile time
}

我没有尝试VS2010,只有2005。