2010-10-27 73 views
2

像語義學我想能夠擁有像C++的Java接口語義。起初,我曾使用boost::signal爲給定事件回調顯式註冊的成員函數。這工作得很好。「界面」像boost :: bind

但是後來我決定一些函數回調池是相關的,抽象它們並立即註冊一個實例的所有相關回調是有意義的。但是我學到的是boost::bind的具體性質和/或採取this的價值似乎使這個突破。或者,也許這只是add_listener(X &x)方法聲明更改boost::bind生成的代碼這一事實。

我有一個非常粗略的理解爲什麼發生問題,我認爲它可能按照其設計正常運行。我很好奇:什麼應該我做了呢?當然有一個正確的方法來做到這一點。

下面是一些示例代碼:

#include <boost/bind.hpp> 
#include <boost/function.hpp> 
#include <iostream> 

using namespace std; 

struct X; 
struct Callback 
{ 
    virtual void add_listener(X &x) = 0; 
}; 

struct X 
{ 
    X() {} 
    X(Callback &c) { c.add_listener(*this); } 
    virtual void go() { cout << "\t'" << __PRETTY_FUNCTION__ << "'" << endl; } 
}; 

struct CallbackReal : public Callback 
{ 
    virtual void add_listener(X &x) 
    { 
     f = boost::bind<void>(boost::mem_fn(&X::go), x); 
    } 

    void go() { f(); } 

    boost::function<void (void)> f; 
}; 


struct Y : public X 
{ 
    Y() {} 

    Y(Callback &c) { c.add_listener(*this); } 
    virtual void go() { cout << "\t'" << __PRETTY_FUNCTION__ << "'" << endl; } 
}; 


int main(void) 
{ 
    CallbackReal c_x; 
    CallbackReal c_y; 

    X x(c_x); 
    Y y(c_y); 

    cout << "Should be 'X'" << endl; 
    boost::bind<void>(boost::mem_fn(&X::go), x)(); 

    cout << "Should be 'Y'" << endl; 
    boost::bind<void>(boost::mem_fn(&X::go), y)(); 

    cout << "------------------" << endl; 

    cout << "Should be 'X'" << endl; 
    c_x.go(); 
    cout << "I wish it were 'Y'" << endl; 
    c_y.go(); 

    return 0; 
} 

好吧,我並沒有完全說明問題。標題具有誤導性。

噢,夥計。 Downvote這一個。我顯然沒有很好地描述這個問題,我認爲這最終歸結爲一個語法錯誤。 :(

+0

什麼是輸出?任何編譯器錯誤/警告? – 2010-10-27 22:51:51

+1

我很困惑,「接口語義」與你在這裏做什麼有關。你爲什麼不使用純粹的抽象基類和虛函數?請參閱:http://www.parashift.com/c++-faq-lite/abcs.html#faq-22.4 – 2010-10-27 23:18:54

+0

好的,現在我很清楚,我已經將幾件事情混淆了,並且在我的示例中給出了不足的細節。我真的*正在使用'boost :: signal'來調用各種註冊的處理程序。爲了使用一個稍微更明確的例子,假設我有一個帶有方法'handleFooEvent','handleBarEvent'和'handleBazEvent'的抽象'EventListener'類。我想註冊一個'EventListener'的實例,並將這些'handle * Event'方法連接到相應的插槽。 – 2010-10-28 02:41:31

回答

3

boost::bind由值並將它們複製需要它的參數。這意味着

f = boost::bind<void>(boost::mem_fn(&X::go), x); 

將經過拷貝的x,這將切下的Y片的它(如果它是一個真正的。Y先跟)爲了得到虛擬調度工作,你需要一個指針傳遞給boost::bind

f = boost::bind(&X::go, &x); 

(注日您實際上並不需要mem_fn,或者明確地寫<void>,因爲boost::bind和參數推導爲您負責。)

0

Java接口在C++中並不存在。最接近你可以得到的是純粹的抽象基類。這通常足夠接近。

您的問題的其餘部分與接口無關。 Java使用Observer模式進行事件連接和分派。界面部分只有輕微的相關性,因爲觀察者需要遵守特定的界面(當然,因爲否則你不知道該怎麼調用)。

使用boost :: bind創建函數實際上是一個超越接口的抽象,因此是一個更通用的解決方案。觀察者模式和函子被放在一起,形成信號/插槽成語/模式,在各種庫中實現,如boost :: signals,boost :: signals2和gtk ++。 Qt版本在機制上有很大不同,但概念相似。

那麼,這是什麼意思,以幫助您瞭解什麼,爲什麼和在哪裏?我建議從搜索Observer模式開始,並嘗試編寫一些實現。