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

时间:2018-05-23 07:51:18

标签: c++ c++03 member-function-pointers

编辑:关于这个话题,我仅限于C ++ 03。

在以下代码中,类Impl派生自Intf并包含类Caller的实例。

Caller的ctor采用Intf::实例和成员函数指针;它在前者Caller::func()中调用后者。

Impl的ctor通过其包含的func()实例注册自身及其成员函数Caller

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

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

我需要排除Caller获取Impl引用和成员函数的可能性; Caller只能了解Intf s而不是Impl s。

// 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中,有必要使用func()将指针限定为成员函数Intf::吗?即为什么这是正确的......

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

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

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

'&amp; Impl :: func'版本的编译器错误是:

  

g ++ -g main.cpp&amp;&amp; ./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

'&amp; 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

1 个答案:

答案 0 :(得分:1)

您可以使用旧方式回调:

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_();