Войти
ПрограммированиеПодсказкиОбщее

Сallback функция класса

Автор:

Иногда необходимо из функции одного класса вызвать функцию обратного вызова другого, при этом не задавая жёстко тип класса, а лишь определяя интерфейс функции(поведение).

class ClassCallback
{
public:
  //Этот метод будет callback-ом 
  int callback(int i)
  {
    return i+1;
  }
};

class Class1
{
public:

  //Шаблон функции - члена
  template <typename T>
  // Первый параметр - ссылка на экземпляр класса, 
  // второй - указатель на функцию - callback
  int foo(T &p, int (T::*fn)(int))
  {
    return (p.*fn)(5); //Вызов функции объекта p
  }
};

int main()
{
  ClassCallback t2;
  Class1 t;

  // Вызов шаблонной функции-члена класса Class1.
  int i = t.foo(t2, &ClassCallback::callback);
}

Нужно только помнить, что шаблонные функции - члены не могут быть виртуальными, ввиду того, что они могут не один раз конкретизироваться.

В случае применения функтора, класса к которому можно применить оператор - (), этот пример можно унифицировать и на обычные функции.

int fooCallback(int i)
{
   return i+1;
}

class ClassCallback
{
public:
  //Этот оператор будет callback-ом 
  int operator () (int i)
  {
    return i+1;
  }
};

class Class1
{
public:

  //Шаблон функции - члена
  template <typename T>
  // Параметр - ссылка на экземпляр класса
  int foo(T &p)
  {
    return p(5); //Вызов оператора  - ()
  }
};

int main()
{
  ClassCallback t2;
  Class1 t;

  // Вызов шаблонной функции-члена класса Class1
  int i = t.foo(t2);
  i = t.foo(fooCallback);
}


Также можно использовать boost::function, функтор позволяющий единообразно объявлять указатели на функции и методы классов.

  //Объявляем функтор с прототипом - int (int)
  boost::function<int (int)> f;

  f = &fooCallback; //Инициализируем указателем на функцию.
  f(5); //Вызываем

  ClassCallback t;
  f = &ClassCallback::callback; //Инициализируем указателем на функцию класса.
  f(&t, 5); //В этом случе необходимо первым параметром передать указатель на объект.

  //В случае "чистого" функтора, вызов не отличается от вызова функции
  ClassCallback t;
  f = boost::bind(&ClassCallback::callback, t, _1);
  f(5);

Теперь в классе который вызывает callback, можно избавиться от шаблонной функции - члена, но в этом случае придётся передавать объекты "чистых" классов функторов.

#C++, #шаблоны

11 июня 2009

Комментарии [2]