2012-10-20 146 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