我目前正在使用Don Clugston的fastdelegates实现一个计时器/回调系统。 (见http://www.codeproject.com/KB/cpp/FastDelegate.aspx)
以下是起始代码:
struct TimerContext
{
};
void free_func( TimerContext* )
{
}
struct Foo
{
void member_func( TimerContext* )
{
}
};
Foo f;
MulticastDelegate< void (TimerContext*) > delegate;
delegate += free_func;
delegate += bind( &Foo::member_func, &f );
好的,但现在,我希望用户能够将TimerContext
子类存储并将自己的结构发送到回调。
这里的目的是防止用户不得不低估TimerContext
他自己
struct TimerContext
{
};
struct MyTimerContext : TimerContext
{
int user_value;
};
void free_func( TimerContext* )
{
}
void free_func2( MyTimerContext* )
{
}
struct Foo
{
void member_func( TimerContext* )
{
}
void member_func2( MyTimerContext* )
{
}
};
Foo f;
MulticastDelegate< void (TimerContext*) > delegate;
delegate += free_func;
delegate += free_func2;
delegate += bind( &Foo::member_func, &f );
delegate += bind( &Foo::member_func2, &f );
正如你猜测的那样,GCC不会让我这样做:)。
error: invalid conversion from `void (*)(MyTimerContext*)' to `void (*)(TimerContext*)'
error: initializing argument 1 of `delegate::Delegate<R ()(Param1)>::Delegate(R (*)(Param1)) [with R = void, Param1 = TimerContext*]'
所以现在我的问题是:
如果我使用reinterpret_cast
强制演员,它会起作用,但它会安全吗?
PS:这些是时间关键的回调,重度虚拟导向解决方案被认为是不切实际的:/
答案 0 :(得分:5)
C ++标准在13.4 / 7中说:
没有标准转换(第4节)指向一个指针到另一个指针。特别是,即使
B
是D
的公共基础,我们也有D* f(); B* (*p1)() = &f; // error void g(D*); void (*p2)(B*) = &g; // error
你仍然可以使用函数适配器来存储使用一个参数的函数指针,例如boost::function
,但我现在还不确定它是否能解决你的问题。
答案 1 :(得分:0)
当然,转换函数指针通常是一个坏主意。
将函数指针从void(*)(Derived*)
转换为void(*)(Base*)
可能有效,也可能无效。如果需要在转换时调整Derived *和Base *指针的内部表示,它肯定不会起作用。但是,如果是单继承关系,则不太可能。仍然,类布局和指针调整是实现定义的,您不应该依赖于此。如果你想承担风险:去看看啊。
假设指针不需要调整,从void(*)(Derived1*)
到void(*)(Base*)
的转换仍然不是一个好主意(不是类型安全的),因为它允许一个期望Derived1 *的函数使用Derived2 *调用,其中Derived1和Derived2是继承层次结构中的兄弟。
答案 2 :(得分:0)
reinterpret_cast
只有在对象的“发送者”和“接收者”对应时才是安全的。因此,如果发送者和接收者是由同一段代码实现的,那么在一段时间内它可能是非常安全的。
如果要将回调添加到委托,和,您希望它们具有不同的类型,就像您一样,您有两个方案:
您在编译时知道所有代表=&gt;你可以将它们包装在一个类型列表中。
代表可以在运行时组成=&gt;您需要使用运行时绑定,即虚函数(exec
方法等)。