2009-10-19 22 views
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:這些是時間關鍵的回調,重面向虛擬的解決方案被認爲是不可行的:/

回答

5

C++標準說,在13.4/7是:

沒有規範的轉化(第4條)的一個指針函數類型轉換爲另一個。特別是,即使BD一個公共的基礎,我們有

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

你仍然可能是可以使用的功能適配器,用於存儲指向同一個參數,像boost::function的功能,但我不現在肯定它是否會解決你的問題。

+0

Howw,好嗎:(感謝您參考! – NewbiZ

+0

即使提振::函數將不會在他的情況下工作,因爲TimerContext *不能隱式轉換到MyTimerContext *。我提到這個類型安全問題,我答案但由於某種原因,我得到了downvoted – sellibitze

0

當然,投射函數指針通常是一個壞主意。

將函數指針從void(*)(Derived*)投射到void(*)(Base*)可能工作,或者它可能不工作。當Derived *和Base *指針的內部表示需要在轉換時進行調整時,它肯定無法工作。但是,如果你的單一繼承關係,這是不可能的。不過,類佈局和指針調整是實現定義的,不應該依賴於此。如果你想冒險:去掉。

假設指針不需要進行調整,從void(*)(Derived1*)void(*)(Base*)轉換仍然不會是一個好主意(不是類型安全的),因爲它允許預期Derived1 *同一個Derived2的調用的函數*其中Derived1和Derived2是繼承層次中的兄弟。

+1

它不是實現定義的,它是未定義的行爲(它有不同的含義) –

+0

不,你誤解了,類佈局和可能的指針調整是實現定義的。 – sellibitze

0

reinterpret_cast只有當對象的'sender'和'receiver'相對應時纔是安全的。因此,如果發送者和接收者使用相同的代碼實現,那麼在一段時間內它可能是相當安全的。

如果你想添加回調委託,你希望他們有不同的類型,因爲你這樣做,你有兩個場景的:

  • 你知道所有與會代表的前期,在編譯時間=>你可以將它們包裝在一個類型列表中。

  • 委託可以在運行時組成=>您需要使用運行時綁定,即虛擬功能(exec方法等)。

相關問題