带派生类的回调的应用程序设计

时间:2014-12-26 19:20:37

标签: c++ c++11

我正在尝试使用参数变化的回调来设计应用程序。有一个中心类Application定义了所有回调。然后是类Connection,它应该存储那些回调(已经绑定)。

Application看起来像这样:

class Application {

public:
  void firstCallback(DerivedFrist *obj) { }
  void secondCallback(DerivedSecond *obj) { }
};

然后有这个Connection类应该存储已注册的回调并在某些内部事件触发时调用它们。

class Connection {

private:
  map<int, ??> callbacks; // what to do if I want it to be typesafe?
public:
  void registerCallback(int condition, Callback callback) {
    callbacks[condition] = callback;
  }

  void fireCallback(int condition, Base *obj) {
    callbacks[condition](obj); // call the callback from the map (with base object?)
  }
};

DerivedFirst和DerivedSecond实例都由内部工厂创建。工厂存储应通过Type<D>类提供给函数的实际类型。工厂中的地图包含conditionType<Base>map<int, Type<Base>>

Type<D>类提供简单的API:allocate - 创建类型的新实例,强制转换 - 将创建的实例强制转换为正确的类型。

工厂代码如下所示:

Base *base = this->factoryMap[condition]->allocate();

然后将对象作为派生对象传递(在演员之后)

问题:

这是我对应用程序的方法,由于类型不同,在尝试使用std :: function时会导致错误。我可能会重新解释这些论点,但这可能会导致未定义的行为。

有没有好的方法来做到这一点?欢迎任何模式。谢谢!

编辑:OP之前提出的This question提供了有关预期设计的更多信息。

2 个答案:

答案 0 :(得分:1)

由于您使用工厂方法为每个Base创建不同的condition,因此您可以修改Base以提供抽象回调接口。

class Base {
public:
    virtual ~Base() {}
    virtual void callback(Application *) = 0;
};

然后,您可以针对该条件从工厂返回的内容调用回调虚拟方法。

您的Connection定义不完整。假设callback持有指向Application中方法的指针,那么只有在提供Application实例时才能调用回调方法。

如果我们假设Connection必须包含注册Application实例的方法,那么Application可能如下所示:

class Application {

    template <typename DERIVED>
    class Factory {
        Base * allocate () { return new DERIVED; }
        //...
    };

    class DerivedFirst : public Base {
        //...
        void callback(Application *) { /* ... */ }
    };

    class DerivedSecond : public Base {
        //...
        void callback(Application *) { /* ... */ }
    };

};

因此,first_condition映射到Application::Factory<Application::DerivedFirst>second_condition映射到Application::Factory<Application::DerivedSecond>

在这种情况下,无需注册回调。它们隐含在工厂生成的Base对象中。 Connection只需要调用它,传入已注册的Application

class Connection {
    Application *app;
public:
    void registerApplication (Application *a) { app = a; }
    void fireCallback (Base *obj) { obj->callback(app); }
};

答案 1 :(得分:0)

假设:

class Base;
class DerivedFirst: public Base { ... };
class DerivedSecond: public Base { ... };

你可以这样做:

class Connection
{
    typedef std::function<void (Base*)> Callback;

    std::map<int, Callback> callbacks;
    ...
}

然后使用std::bind绑定对象成员函数,例如:

Application application;
Connection connection;

connection.registerCallback(42, std::bind(&Application::firstCallback, &application, std::placeholders::_1);