c++ - 注册类的不同实例如何分配不同的成员函数指针?

标签 c++ c++03 pointer-to-member

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

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

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

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

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

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

我需要排除 Caller 接受 Impl 引用和成员函数的可能性; Caller 只能知道 Intf 而不知道 Impl

// 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 的构造函数中,有必要使用 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_();

关于c++ - 注册类的不同实例如何分配不同的成员函数指针?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50482753/

相关文章:

c++ - 不退出以 cin 为条件的 while 循环 c++

c++ - 动态选择模板特化

c++ - 使用 SFINAE 作为模板化构造函数时遇到问题

不使用 std::bind、std::function 或 boost 的 C++ 多成员函数回调

c++ - 如何将函数指针的 std::vector 初始化为运算符重载?

c++ - C++中非模板类的特化成员函数

c++ - 对服务器/客户端应用程序使用 Kerberos 身份验证

c++ - 基类可以声明一个虚方法但不定义它吗?仍然在派生类中定义

使用夹具的 C++ GoogleTest - 函数指针定义不可访问

c# - C#和C++之间的进程间通信