TAG

首都機能移轉 (2) 歌詞 (2) 靠北文 (40) 戲言 (30) 糟糕 (7) ACG (23) Assembly (2) Boost (2) C (31) C++ (69) CMake (4) CSIE (67) Debian (34) Design_Pattern (2) Django (1) Eclipse (1) en_US (13) FFmpeg (3) FoolproofProject (26) FreeBSD (2) Git (4) GNU_Linux (65) IDE (5) Java (11) JavaScript (19) KDE (15) Khopper (16) KomiX (3) Kubuntu (18) Life (1) Lighttpd (2) Mac_OS_X (2) Opera (1) PHP (2) PicKing (2) Programing (21) Prolog (1) Python (7) QSnapshot (2) Qt (30) Qt_Jambi (1) Regular_Expression (1) Shell_Script (7) Talk (98) VirtualBox (7) Visual_Studio (13) Windows (18) zh_TW (36)

2009年11月5日 星期四

A way to use C++ object in C callback

前幾天在用 libFLAC 的時候[?],它要求 client 註冊一個 callback 給它,prototype 長這樣:
typedef FLAC__StreamDecoderWriteStatus
(* FLAC__StreamDecoderWriteCallback)
(const FLAC__StreamDecoder *decoder,
const FLAC__Frame *frame,
const FLAC__int32 *const buffer[],
void *client_data);
看起來很複雜,其實不會,就是個 function pointer 的 typedef 而己[?]
可以看到最後一個 void * client_data 是用來接受 client 的資料用的,先接 void * 再轉成自己要的型別,算是 C 的老手法了。
Well, 在 C++ 上使用時就沒有那麼簡單。第一個問題是 member function 需要實體才能使用。
簡單一個想法是宣告一個 struct,把實體和 pointer to member function 包起來,再傳給這個 callback function。不過一來這有點麻煩,二來你不能呼叫用 protected 或 private 修飾的 members。
沒關係,我們有 friend!
嗯,不好意思,這的確是可以動,不過真的很爛。
還好我們還有另一顆子彈,就是 static member function。static member 不需要實體,且 member function 可以存取 class 內所有 member,這樣就一次解決了兩個問題。
所以我們的 callback 會長這樣:
static FLAC__StreamDecoderWriteStatus
FlacReader::writeCallback_
(const FLAC__StreamDecoder *decoder,
const FLAC__Frame *frame,
const FLAC__int32 *const buffer[],
void *client_data) {
    FlacReader * self = static_cast< FlacReader * >( client_data );
    // blah blah
}
client_data 那裡傳 this 就好。
不要譴責我沒用 dynamic_cast,我百分之百確定 client_data 是 FlacReader 好嗎?

2 則留言:

  1. 這不是 coder 卻不確定 binary object (which is pointed to by a void pointer) 的實際型別的問題. 這個狀況用不了 dynamic_cast.

    回覆刪除
  2. 對啊 ... 有些書的建議把 dynamic_cast 無限上綱,好像多型指標不用 dynamic_cast 就一定爆炸。如果完全確定它指向哪個型別,我想用 static_cast 就夠了。

    回覆刪除