C ++回调到非静态接口方法

时间:2011-10-03 16:12:28

标签: c++ function-pointers

我有一个A类应该从接口类B调用非静态类方法,其签名由以下函数指针表示:

bool (B::*check)(int) const

这种方法将由一组实现B的类{C}实现,每个类具有与上述签名匹配的多个方法。因此,我需要将回调从A绑定到B,然后B将委托给C中选择的方法。

使用某些代码编辑:

这是我的想法草图。请注意,这只是上述要求的一个示例,代码组织中的任何内容都不是强制性的,可能是A类。

class B {
  public:
    bool check(int val) const {
       // call to a binded method with a given signature (sig) on a Cx class
       ...
    }
};

class C1: public B {
  ...
  // a method implementing the (sig) signature
  // another method implementing the (sig) signature
};


class C2: public B {
  ...
  // a method implementing the (sig) signature
  // another method implementing the (sig) signature
};

class A {
  public:
  ...
  private:
    bool result;
    int val;

    void call_check(B const& b) const {
      result = b.check(val);      
    }
  ...
};

这可能在C ++中?或者等价地,什么是允许A只知道B类的解决方案?

令我困惑的是,我还没有找到解决这个特殊需求的解决方案。

4 个答案:

答案 0 :(得分:1)

大量修改

我认为我得到了你想要的东西,基于一些沉重的类型铸造。

请注意,我 NOT 推荐此技巧。虽然我的例子有效,但我相信这里有一些很大的陷阱可能会让事情搞砸。

与以前一样,类A可以同时接受正确签名的方法和类型为B的对象,或者来自类型B的对象,例如C }),并在指定的对象上调用指定的方法。

B实际上根本没有任何方法,只能作为两个类C1&的公共基类。 C2

底部是main,演示了如何使用它。我遗漏了两个SetCallback***方法的实现,因为它们很简单。

class B
{   public: // Has nothing, only serves as base-class for C1 and C2.        
};

class C1: public B
{
    public: bool DoThis(int x) const { return true; }
};

class C2: public B
{
    public: bool DoThat(int x) const { return false; }
};

class A
{
    private:
        bool (B::*m_check)(int) const;
        B* m_Obj;

    public:
        void SetCallbackFunction(bool (B::*fnc)(int) const)
        {   m_check = fnc; }

        void SetCallbackObject(B* pB)
        {   m_Obj = pB;  }

        bool InvokeCallback(int val)
        {
            return (m_Obj->*m_check)(val);
        }
};

int _tmain(int argc, _TCHAR* argv[])
{
    A a;
    C1 c;

    bool (C1::*func)(int) const;
    bool (B::*b_func)(int) const;

    func = &C1::DoThis;
    b_func = (bool (B::*)(int) const)(func);   // Dangerous Typecasting.  Use caution!

    a.SetCallbackFunction(b_func);
    a.SetCallbackObject((B*)(&c));   // A simpler, safer typecast.

    a.InvokeCallback(5);  // Ends up calling C1::DoThis.

    _getch();
    return 0;
}

答案 1 :(得分:1)

您可以做的最简单的事情是不使用成员函数指针,而是使用更高阶的构造,如functionboost或C ++ 11),并使用{{注册回调1}}(再次,bind或C ++ 11)。

答案 2 :(得分:1)

指针到成员功能可用,并且可以完全按照您的要求进行操作。但是,请注意它们实际上并不是“指针”,而是“指针式”,因为可能正确的查找/调用必须通过“vptr”表关联与一个可能有多于一个父母的类。

简而言之:是的,你可以拥有它。如果在模板中实现,则需要包含目标标头(但 需要在代码扩展时实现目标类标头)。如果您实现为非模板,那么可以转发声明成员函数并使其工作。或者,您可以简单地包含目标类类型标题。

由于有多个目标函数可用,是的,在实际绑定时,必须包含标题(如果这是模板实现,则不需要标题):

class MyA {
public:
  bool foo1(int) const;
  bool foo2(int) const;
};

void MyFunc(void) {
  bool (MyA::*my_ptr_to_func)(int) const;
  my_ptr_to_func = &MyA::foo2;

  MyA my_a;

  // call it
  if((my_a.*my_ptr_to_func)(42))
  {
    // ...
  }
}

[更新] ,根据您更新的代码,您似乎只想让“bool B::check(int) const”成为基类中的“virtual”,并且在派生的“C1”和“C2”类中覆盖/重新实现该函数?

是的,virtual函数将被调用(C1C2类中的实现),即使您的指针最初是B::check(int)函数。这是有效的,并且正是为什么指向成员函数的指针不是完全指针,而是指针式(允许)您调用以在派生类中正确执行virtual代码。)

所以,不要害怕:它会起作用,只需将“virtual”放在B::check(int)的基础上。

答案 3 :(得分:0)

听起来你想使用观察者模式允许A持有bool (B::*check)(int) const类型的函数指针向量。

{C}中的类可以通过观察者模式注册到A.我不明白为什么你需要一个接口B,如果你使用这种形式的模式。接口将由需要签名所选函数指针的函数指针向量保证。