3

我目前正在使用 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:这些是时间关键的回调,重的面向虚拟的解决方案被认为是不切实际的:/

4

3 回答 3

5

C++ 标准在 13.4/7 中说:

没有将一种指向函数的指针类型转换为另一种的标准转换(第 4 条)。特别是,即使B是 的公共基础D,我们也有

D* f();
B* (*p1)() = &f;  // error
void g(D*);
void (*p2)(B*) = &g;  // error

您仍然可以使用函数适配器来存储指向带有一个参数的函数的指针,例如boost::function,但我现在不确定它是否会解决您的问题。

于 2009-10-19T17:20:57.817 回答
0

reinterpret_cast只有当对象的“发送者”和“接收者”对应时,它才是安全的。因此,如果发送者和接收者是由同一段代码实现的,那么在一段时间内它可能是相当安全的。

如果您想向委托添加回调,并且希望它们具有不同的类型,就像您所做的那样,您有两种情况:

  • 您在编译时预先知道所有代表 => 您可以将它们包装在类型列表中。

  • 委托可以在运行时组成=>您需要使用运行时绑定,即虚拟函数(exec方法等)。

于 2009-10-19T17:27:37.697 回答
0

当然,转换函数指针通常是一个坏主意。

void(*)(Derived*)从to转换函数指针void(*)(Base*)可能有效,也可能无效。如果需要在转换时调整 Derived* 和 Base* 指针的内部表示,它肯定不会起作用。但是,在您的单一继承关系的情况下,这不太可能。尽管如此,类布局和指针调整是实现定义的,您不应该依赖它。如果你想冒险:去吧。

假设不需要调整指针,从void(*)(Derived1*)to的转换void(*)(Base*)仍然不是一个好主意(不是类型安全的),因为它允许使用 Derived2* 调用期望 Derived1* 的函数,其中 Derived1 和 Derived2 是继承层次。

于 2009-10-19T17:22:20.580 回答