2012-10-20 150 views
1

注意:下面的代碼示例不是真正的代碼,真正的代碼在這裏粘貼起來要複雜得多,所以這個例子看起來很荒謬,但並不重要。用於重載成員函數的成員函數指針

struct Base 
{ 
    void beginEvent(int a) 
    { 
     impl(a, &Base::onBeginEvent, &Base::onBeginEvent); 
    } 

    void endEvent(int a) 
    { 
     impl(a, &Base::onEndEvent, &Base::onEndEvent); 
    } 

    void impl(int a, void (Base::*func1)(int), void (Base::*func2)(int, int)) 
    { 
     //some complicated behavior 
     //... 
     (this->*func1)(a); 
     (this->*func2)(a, -a); 
    } 

    virtual void onBeginEvent(int a){} 
    virtual void onBeginEvent(int a, int negativeA){} 
    virtual void onEndEvent(int a){} 
    virtual void onEndEvent(int a, int negativeA){} 
}; 

struct Derived : public Base 
{ 
    void onBeginEvent(int a) { std::cout << a << "\n"; } 
    void onEndEvent(int a, int b) { std::cout << a << "==(-(" << b << "))\n"; } 
}; 

int main() 
{ 
    Derived d; 

    d.beginEvent(3); 
    d.endEvent(9); 

    return 0; 
} 

我的問題是: 是真的有必要定義impl功能需要void (Base::*func1)(int)void (Base::*func2)(int, int)的方式,即使我知道這是一個成員函數指針(&Base::onBeginEvent在這種情況下, )?

當只提供其中一個我顯然得到太少resp。在打電話時要多加爭論。我不想要可變參數函數或其他東西,我想要有限數量的可以Base提供給Derived的方法。派生可能只需要一個,或者提供的方法的任何子集被調用。但我知道,它們只會在同一個符號上超載。我的目標不是讓它適用於一些瘋狂的解決方法,我只想知道,如果我可以減少發佈的代碼。

Full ideone working example

編輯 THME在我真正的代碼實現了一套方法是相當複雜的,芽的開始,只是與IMPL年底不同的呼叫結束同...

回答

0

你說...the way it takes void (Base::*func1)(int) and void (Base::*func2)(int, int) even though I know that it is one member function pointer...,誰告訴你他們都是一個功能?僅僅因爲2個函數具有相同的名稱,它永遠不意味着它們是相同的函數。 他們的地址和除了他們的名字以外的所有東西都不同。所以他們是2個不同的功能不是一個功能

+3

物質是正確的,但我覺得音調是不必要的苛刻。 –

+1

謝謝你指出。雖然答案是什麼?沒有辦法將'impl(a,&Base :: onBeginEvent,&Base :: onBeginEvent);'改成'impl(a,&Base :: onBeginEvent);'? – relaxxx

+0

當然不是!你可以使用其他函數'foo',並且永遠不會改變它們與不相關函數的事實,其中一個函數可以發送宇宙飛船到月球,其他人則試圖找到一個小偷。唯一導致你感覺他們有聯繫的是他們有相同的名字。但是,計算機,特別是我們可愛的C++能夠理解它嗎?但是你可以編寫一個宏來爲你編寫,如果你真的想要它 – BigBoss

1

如何更換具有多態行爲的函數指針,這是實際上相同的事情,但更多的面向對象,更直觀,更容易閱讀。

下面是一個例子:

struct Base 
{ 
    void beginEvent(int a) 
    { 
     implBegin(a); 
    } 

    void endEvent(int a) 
    { 
     implEnd(a); 
    } 

// Consider making the rest of the methods protected  
// protected: 

    // This is effectively a Template Method Design pattern 
    // This method may not be necessary, in which case just 
    // move the code to beginEvent() 
    void implBegin(int a) 
    { 
     onBeginEvent(a); 
     onBeginEvent(a, -a); 
    } 

    // This is effectively a Template Method Design pattern 
    // This method may not be necessary, in which case just 
    // move the code to endEvent() 
    void implEnd(int a) 
    { 
     onEndEvent(a); 
     onEndEvent(a, -a); 
    } 

    virtual void onBeginEvent(int a){} 
    virtual void onBeginEvent(int a, int negativeA){} 
    virtual void onEndEvent(int a){} 
    virtual void onEndEvent(int a, int negativeA){} 
}; 

struct Derived : public Base 
{ 
    // Notice I defined these as virtual 
    virtual void onBeginEvent(int a) { std::cout << a << "\n"; } 
    virtual void onEndEvent(int a, int b) { std::cout << a << "==(-(" << b << "))\n"; } 
}; 

int main() 
{ 
    Derived d; 

    d.beginEvent(3); 
    d.endEvent(9); 

    return 0; 
} 

注意implBegin()和impleEnd()可能不是必要的, 你可能只是做同樣的事情在beginEvent()和ENDEVENT() 這裏有一個鏈接Template Method設計模式。

另一種方法是將Base定義爲is,但可能將其稱爲EventManager,並創建EventHandlers的類層次結構,可能是EventBase和EventDerived。 EventHandlers可以被注入到EventManager中(通過setEventHandler()方法)。

+0

我不太確定impl方法在這裏做什麼,因爲它們是非虛擬的。您可以直接從begin/endEvent方法調用onBegin/onEnd。此外,在Base中,您應該使onBegin/onEnd方法爲純虛擬,以避免直接實例化Base。 – chradcliffe

+0

@chradcliffe你即將implBegin /結束正確的,這就是爲什麼我把一個評論,大意代碼後(尋找「請注意......」)我會添加代碼註釋。關於純粹的虛擬方法,這確實是相當標準的,但它僅取決於應用程序,OP可以/應該適應性地適應。 – Brady

+0

@chradcliffe關於你對impl方法非虛擬化的評論,我不確定你的觀點是什麼,他們不需要是虛擬的就可以調用它們。應該是虛擬的方法是onBeginEvent()和onEndEvent()。 – Brady