我正在尝试使用参数变化的回调来设计应用程序。有一个中心类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>
类提供给函数的实际类型。工厂中的地图包含condition
和Type<Base>
(map<int, Type<Base>>
)
Type<D>
类提供简单的API:allocate - 创建类型的新实例,强制转换 - 将创建的实例强制转换为正确的类型。
工厂代码如下所示:
Base *base = this->factoryMap[condition]->allocate();
然后将对象作为派生对象传递(在演员之后)
问题:
这是我对应用程序的方法,由于类型不同,在尝试使用std :: function时会导致错误。我可能会重新解释这些论点,但这可能会导致未定义的行为。
有没有好的方法来做到这一点?欢迎任何模式。谢谢!
编辑:OP之前提出的This question提供了有关预期设计的更多信息。答案 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);