2

我没有太多在 C++ 中使用函数数组的经验。我需要使用一个函数数组,其中数组包含来自不同对象的函数。这是一些虚拟代码来说明我想要实现的内容。

class base_class
{
public:
  virtual int function1(int arg1, int arg2);
  virtual int function2(int arg1, int arg2);
};

class derived_class : public base_class
{
public:
  int function1(int arg1, int arg2) { /* ... */ };
  int function2(int arg1, int arg2) { /* ... */ };
  // ...
};

typedef int (*functions) (int arg1, int arg2); 

int main()
{
  derived_class object1;  
  derived_class object2;  

  functions func_instance[4];
  func_instance[0] = object1.function1;
  func_instance[1] = object1.function2;
  func_instance[2] = object2.function1;
  func_instance[3] = object2.function2;
  // ...
}

我无法让它工作,它会引发以下错误:

error: argument of type int () (int , int) does not match int (*) (int, int)
4

1 回答 1

9

The easiest way is to use std::function and std::bind.

#include <functional>
#include <array>

derived_class object1;
derived_class object2;

std::array< std::function<int(int, int)>, 2> > 
  arr = {{ std::bind(&derived_class::function1, &object1)
         , std::bind(&derived_class::function2, &object1)}};
         // and so on

Note that object1 and object2 have been bound by address. You need to keep them alive as long as the bound functions are alive. If you just write object1 in the bind expression a copy of the object will be stored in the bound function and no scope problems will occur.

C++03 A complete example with a hand-rolled, single-purpose binder-type:

#include <iostream>

struct base
{
  virtual void f0() { std::cout << "f0 base" << std::endl; }
  virtual void f1() { std::cout << "f1 base" << std::endl; }
};

struct derived : base
{
  void f0() { std::cout << "f0 derived" << std::endl; }
  void f1() { std::cout << "f1 derived" << std::endl; }
};

// typedef for a Pointer to a member function 
// of base that accepts arguments and returns void
typedef void (base::*MemberPtrType)(void);

// we pack a pointer to a class and a pointer to a member function together
struct binder
{
  MemberPtrType ptr;
  base*         base;

  // shortcut to call this thing, you might also want 
  // to have an overload of operator() and a result_type typedef
  void call()
  { ((base)->*(ptr))(); }
};


int main()
{
  base b;
  derived d;

  // initialize a 4 element array of binder, the first argument is the function,
  // the second is the object to call it on
  // 
  // remember that b and d need to be alive as long as 
  // you want to call something in this array
  binder arr[4] = { {&base::f0, &b}, {&base::f1, &b}, 
                    {&base::f0, &d}, {&base::f1, &d}};

  // now walk through the array and call each
  for(binder* begin = arr; begin != arr + 4; ++begin)
  {
    begin->call();
  }


  return 0;
}
于 2013-05-14T07:17:44.843 回答