绕过模板化事件的虚函数

时间:2015-08-26 18:00:31

标签: c++ templates observer-pattern virtual-functions

我基本上试图实现一般的观察者模式。

class Observer {
public:
    template <class T>
    virtual void OnEvent(const EventHandle& h, T& affectedItem) = 0;
};

class Subject {
public:
    void AddObserver(Observer* o) {
        observers.Add(o);
    }
    void RemoveObserver(Observer* o) {
        observers.Remove(o);
    }
    template <class T>
    void Notify(const EventHandle& h, T& affectedItem) {
        for (Observer* o : observers) {
            o->OnEvent(h, affectedItem);
        }
    }
private:
    set<Observer*> observers;
};

Observer::OnEvent()中,我想获取事件中受影响的项目(比如说我只是在库存中添加了一些东西,需要反映GUI中的添加内容 - 我会打电话Subject::Notify(itemAddedEvent, newItem))。我知道我需要对课程进行一些重构/重新设计,但我仍然坚持如何做。有什么方法可以解决这个问题?

2 个答案:

答案 0 :(得分:1)

不幸的是,正如您在编译时可能看到的那样,它不允许拥有虚拟功能的模板。

当你选择了虚函数时,我猜你打算以某种方式使用多态。如果是这种情况,您可以使用继承完美地使用无临时实现。唯一的限制是您的不同actor继承您的泛型类。但是由于可能的多重继承,他不是一个强大的约束。

观察者看起来像(我为受影响的物品使用了主题,但你可以使用第三类):

class Subject; 
class Observer {
public:
    virtual void OnEvent(const EventHandle& h, Subject& affectedItem) = 0;
    virtual ~Observer() {}  // virtual function ? => better foresee a virtual destructor
};

obervee几乎保持不变:

class Subject {
public:
    ...
    void Notify(const EventHandle& h, Subject& affectedItem) {
        for (Observer* o : observers) {
            o->OnEvent(h, affectedItem);
        }
    }
private:
    set<Observer*> observers;
};

使用类将如下:

struct ConcreteObserverA : Observer {
    void OnEvent(const EventHandle& h, Subject& affectedItem) override {
        cout<<"A:"<<&affectedItem<<endl;
    }
struct ConcreteSubjectSA : Subject { };

这是live demo

答案 1 :(得分:0)

真的需要一个快速的解决方案,所以想出了这个。我意识到这非常hacky,我可能正在摧毁编程的原理,并且应该把我的计算机抛到窗外以赎罪,甚至建议将其作为解决方案等等,但它确实完全符合我的要求和很容易理解,所以现在我要继续使用它,直到出现更好的东西。

基本上我只是在对象中包装(可能是原始的)数据:

struct ParamBase {};

template <class T>
struct ConcreteParam : ParamBase {
    T data;
    ConcreteParam(T t) : data(t) {}
};

class Observer {
public:
    virtual void OnEvent(const EventHandle& h, const ParamBase& affectedItem) = 0;
protected:
    template <class T>
    T getParamData(const ParamBase& p) {
        const ParamBase* pb = &p;
        return ((ConcreteParam<T>*)pb)->data;
    }
};

class Subject {
public:
    // Add/Remove functions stripped
    template <class T>
    void Notify(const EventHandle& h, T affectedItem) {
        for (Observer* o : observers) {
            o->OnEvent(h, ConcreteParam<T>(affectedItem));
        }
    }
};

使用示例:

class InventoryUI : public Observer {
public:
    virtual void OnEvent(const EventHandle& h, const ParamBase& affectedItem) {
        if (h == itemRemovedEvent) {
            int index = getParamData<int>(affectedItem);
            removeItemAt(index);
        }
        else if (h == itemAddedEvent) {
            Item* item = getParamData<Item*>(affectedItem);
            addItemToGrid(item);
        }
    }
};