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

发布于 2024-12-07 13:10:09 字数 970 浏览 0 评论 0原文

我有一个类 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 类的解决方案是什么?

令我困惑的是,我还没有找到解决这个非常具体的需求的解决方案。

I have a class A that should call a non-static class method from an interface class B, with signature expressed by, say, the following function pointer:

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

Such method would be implemented by a set of classes {C} implementing B, each with multiple methods matching the above signature. I therefore need to bind the callback from A towards B, which in turn would delegate to the chosen method from C.

Edited with some code:

This is a sketch of what I have in mind. Beware that this is only an example of the requirement above, nothing in the organization of the code is mandatory outside, perhaps, class 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);      
    }
  ...
};

It that possible in C++? Or equivalently, what would be a solution that allows A to know of class B only?

To my puzzlement, I haven't found a solution around for this very specific need.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

橘寄 2024-12-14 13:10:10

大规模编辑

我想我得到了你想要的,基于一些大量的类型转换。

请注意,我推荐这种技术。尽管我的示例有效,但我相信这里存在一些大陷阱,可能真的会把事情搞砸。

和以前一样,类 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;
}

Massive Edit

I think I got what you want, based on some heavy type-casting.

Note that I do NOT recommend this technique. Although my example works, I believe there are some big pitfalls here that could really screw things up.

As before, Class A can accept both a method of the proper signature and an object (of type B, or derived from type B, such as your C classes), and call the specified method on the specified object.

Class B does not actually have any methods at all, and only acts as a common base-class for the two classes C1 & C2.

At the bottom is a main that demonstrates how this is used. I left out the implementation of the two SetCallback*** methods, as they're trivial.

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;
}
蓝礼 2024-12-14 13:10:10

您可以做的最简单的事情就是不要使用成员函数指针,而是使用更高阶的构造,例如 functionboost 或 C++11)并注册回调与 bind (同样,boost 或 C++11)。

The simplest thing you can do is not to use a member function pointer, but rather a higher order construct like function (either boost or C++11) and register the callbacks with bind (again, boost or C++11).

源来凯始玺欢你 2024-12-14 13:10:10

可以使用指向成员函数的指针,并且可以完全按照您的要求进行操作。但是,请注意它们实际上并不是“指针”,而是“类似指针”,因为正确的查找/调用可能必须通过关联的“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))
  {
    // ...
  }
}

[UPDATE],基于您更新的代码,似乎您只想在基类中将“bool B::check(int) const”设为“virtual”,然后覆盖/在派生中重新实现该函数“C1”和“C2”类?

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

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

Pointers-to-member-functions are available, and do exactly what you want. However, just be aware that they are not actually "pointers", but are "pointer-like", since it is possible that proper lookup/calling must go through the "vptr" table(s) associated with a class that may possibly have more-than-one-parent.

In short: Yes, you can have it. If you implement in a template, you do not need to include the target headers (but you would need to implement the target class headers at the point of code expansion). If you implement as a non-template, then you could forward-declare the member functions and get it to work. Or, you could simply include the target class-type headers.

Since multiple target functions are available, yes, at the point of actual binding, you must include the header (you don't need the header if this is a template implementation):

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))
  {
    // ...
  }
}

[UPDATE], based on your updated code, it seems like you merely want to make "bool B::check(int) const" to be "virtual" in the base class, and override/re-implement that function in the derived "C1" and "C2" classes?

Yes, the virtual function will be called (the implementation in the C1 and C2 classes), even though your pointer was originally to the B::check(int) function. This works, and is exactly why a pointer-to-member-function is not exactly a pointer, but is pointer-like (to permit your call to correctly execute the virtual code in the derived classes).

So, no fear: It will work, just put "virtual" on B::check(int) in the base.

入怼 2024-12-14 13:10:10

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

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

It sounds like you want to use the observer pattern to allow A to hold a vector of function pointers of type bool (B::*check)(int) const.

Classes in {C} could thus register through the observer pattern to A. I don't see why you need an interface, B, explicitly if you use this form of pattern. The interface will be guaranteed by the vector of function pointers requiring the signature of your chosen function pointer.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文