如何将不同的成员函数指针赋值给不同的注册实例类?

How to assign different member function pointers to different instances of registering classes?

编辑:我在这个话题上仅限于 C++03。

在下面的代码中,class Impl 派生自 Intf 并包含 class Caller.

的实例

Caller的ctor接受一个Intf::实例和成员函数指针;它在 Caller::func().

中对前者调用后者

Impl 的构造函数将自身及其成员函数 func() 注册到其包含的 Caller 实例。

我希望 Impl 包含多个 Caller 实例并为每个实例注册不同的成员函数指针,以便调用每个包含的 Caller 实例的 ::func() 结果正在调用一个不同的 Impl 成员函数 - 这可以做到吗?

我能想到的唯一方法是在 Intf 中定义多个纯虚函数,在 Impl 中实现它们并注册那些覆盖函数。但这对我来说不是一个理想的解决方案:我想知道是否有一种方法可以在注册 class 的不同实例中注册不同的成员函数指针,而无需在接口 class 1:1 在实现中具有覆盖功能 class.

我需要排除 Caller 采用 Impl 引用和成员函数的可能性; Caller 只能知道 Intfs 而不能知道 Impls。

// main.cpp
#include <iostream>

class Intf
{
public:

  virtual void func() = 0;

  typedef void (Intf::*funcPtr)();
};

class Caller
{
public:

  Caller( Intf& f, Intf::funcPtr func ) : f_( f ), func_( func ) {}

  void func() { f_.func(); }

private:

  Intf& f_;
  Intf::funcPtr func_;
};

class Impl : public Intf
{
public:

  Impl()
    : c_ ( *this, &Intf::func )
//    , c2_( *this, static_cast<Intf::funcPtr>(func2) )
  {
  }

  void callCaller() { c_.func(); };

//  void callCaller2() { c2_.func(); };

private:

  void func()
  {
    std::cout << __FUNCTION__ << std::endl;
  }

  void func2()
  {
    std::cout << __FUNCTION__ << std::endl;
  }

  Caller c_;
//  Caller c2_;
};

int main( int argc, char* argv[] )
{
  Impl i;
  i.callCaller();
  return 0;
}

另一个问题:有人可以解释为什么在 Impl 的 ctor 中,有必要用 Intf:: 限定指向成员函数 func() 的指针吗? IE。为什么这是正确的...

Impl() : c_ ( *this, &Intf::func ) {}

...为什么这些不正确...

Impl() : c_ ( *this, &Impl::func ) {}
Impl() : c_ ( *this, &func ) {}

?

“&Impl::func”版本的编译器错误是:

g++ -g main.cpp && ./a.out

main.cpp: In constructor 'Impl::Impl()':
main.cpp:31:31: error: no matching function for call to 'Caller::Caller(Impl&, void (Impl::*)())'
     : c_ ( *this, &Impl::func )
                               ^
main.cpp:31:31: note: candidates are:
main.cpp:16:3: note: Caller::Caller(Intf&, Intf::funcPtr)
   Caller( Intf& f, Intf::funcPtr func ) : f_( f ), func_( func ) {}
   ^
main.cpp:16:3: note:   no known conversion for argument 2 from 'void (Impl::*)()' to 'Intf::funcPtr {aka void (Intf::*)()}'
main.cpp:12:7: note: Caller::Caller(const Caller&)
 class Caller
       ^
main.cpp:12:7: note:   candidate expects 1 argument, 2 provided

“&func”版本的编译器错误是:

>g++ -g main.cpp && ./a.out
main.cpp: In constructor 'Impl::Impl()':
main.cpp:31:20: error: ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function.  Say '&Impl::func' [-fpermissive]
     : c_ ( *this, &func )
                    ^
main.cpp:31:25: error: no matching function for call to 'Caller::Caller(Impl&, void (Impl::*)())'
     : c_ ( *this, &func )
                         ^
main.cpp:31:25: note: candidates are:
main.cpp:16:3: note: Caller::Caller(Intf&, Intf::funcPtr)
   Caller( Intf& f, Intf::funcPtr func ) : f_( f ), func_( func ) {}
   ^
main.cpp:16:3: note:   no known conversion for argument 2 from 'void (Impl::*)()' to 'Intf::funcPtr {aka void (Intf::*)()}'
main.cpp:12:7: note: Caller::Caller(const Caller&)
 class Caller
       ^
main.cpp:12:7: note:   candidate expects 1 argument, 2 provided

您可以使用旧的回调方式:

typedef void (*callback_t)(void*);

辅助函数:

template <typename C, void (C::*M)()>
void member_func(void* instance)
{
    C* c = static_cast<C*>(instance); // Not typesafe :-/
    ((*c).*M)();
}

然后

class Caller
{
public:
    Caller(Intf& f, callback_t func) : instance(f), func_(func) {}

    void func() const { func_(&instance); }
private:
    Intf& instance;
    callback_t func_;
};

class Impl : public Intf
{
public:
    Impl()
      : c_  ( *this, &member_func<Intf, &Intf::func> )
      , c2_ ( *this, &member_func<Impl, &Impl::func2> )
  {
  }
// ...
};

Demo

自 C++11 起,您可以将 Caller 替换为 std::function<void(void)> 并通过 c2_([=](){ this->func2();}) 对其进行初始化。并称之为 c2_();