Как реализовать обратный вызов в C ++?

Коллекция - довольно неправильный объект для сортировки.

Сама точка коллекции - обеспечить очень быстрый доступ к определенному элементу, идентифицированному ключом.

Вы можете захотеть использовать массивы вместо коллекций, если вам действительно нужна сортировка.


Кроме этого, да, вы могут сортировать элементы в коллекции. Вам необходимо использовать любой алгоритм сортировки, доступный в Интернете (вы можете использовать Google в целом на любом языке) и внести незначительные изменения там, где происходит своп (другие изменения не нужны, поскольку коллекции vba, например массивы, могут быть доступны с индексами). Чтобы поменять два элемента в коллекции, вам необходимо удалить их из коллекции и вставить их обратно в правильные позиции (используя третий или четвертый параметр метода Add).

13
задан nacho4d 1 August 2010 в 12:17
поделиться

6 ответов

Лучшее решение, используйте boost :: function с boost :: bind , или если ваш компилятор поддерживает tr1 / c ++ 0x используйте std :: tr1 :: function и std :: tr1 :: bind .

Все становится так просто, как:

boost::function<void()> callback;
Target myTarget;
callback=boost::bind(&Target::doSomething,&myTarget);

callback(); // calls the function

И ваш обратный вызов set выглядит следующим образом:

class MyClassWithCallback{
public:
  void setCallback(boost::function<void()> const &cb)
  {
     callback_ = cb;
  }
  void call_it() { callback_(); }
private:
  boost::function<void()> callback_;
};

В противном случае вам нужно реализовать некоторый абстрактный класс

struct callback { 
 virtual void call() = 0;
 virtual ~callback() {}
};

struct TargetCallback {
 virtual void call() { ((*self).*member)()); }
 void (Target::*member)();
 Target *self;
 TargetCallback(void (Target::*m)(),Target *p) : 
       member(m),
       self(p)
 {}
};

А затем использовать:

myCaller.setCallback(new TargetCallback(&Target::doSomething,&myTarget));

Когда ваш класс будет изменен в:

class MyClassWithCallback{
public:
  void setCallback(callback *cb)
  {
     callback_.reset(cb);
  }
  void call_it() { callback_->call(); }
private:
  std::auto_ptr<callback> callback_;
};

И, конечно, если функция, которую вы хотите вызвать, не меняется, вы можете просто реализовать какой-то интерфейс, то есть получить Target из некоторого абстрактного класса с помощью этого вызова.

16
ответ дан 1 December 2019 в 19:07
поделиться

Также просмотрите сигналы и слоты шаблона наблюдателя и и слоты . Это распространяется на нескольких подписчиков.

3
ответ дан 1 December 2019 в 19:07
поделиться

Шаблон проектирования Observer , кажется, именно то, что вам нужно.

5
ответ дан 1 December 2019 в 19:07
поделиться

В C++ указатели на методы класса практически не используются. То, что вы позвонили – это делегаты и использовать их не рекомендуется. Вместо них необходимо использовать виртуальные функции и абстрактные классы. Однако C++ не был бы так любим мной, если бы не поддерживал совершенно другие концепции программирования. Если вам все еще нужны делегаты, вы должны обратить внимание на «boost functional» (часть C + +0 x), он позволяет указывать на методы классов независимо от имени класса. Кроме того, в C++ Builder есть тип __closure - реализация делегата на уровне компилятора.

P.S. Извините за плохой английский...

2
ответ дан 1 December 2019 в 19:07
поделиться

Один из приемов состоит в том, чтобы вместо этого использовать интерфейсы, так что вам не нужно специально знать класс в вашем 'MyClassWithCallback', если переданный объект реализует интерфейс.

например. (псевдокод)

struct myinterface
{
  void doSomething()=0;
};

class Target : public myinterface { ..implement doSomething... };

и

myinterface *targetObj; 
void setCallback(myinterface *myObj){
    targetObj = myObj;
};

выполняют обратный вызов

targetObj->doSomething();

, устанавливая его:

Target myTarget;
MyClassWithCallback myCaller;
myCaller.setCallback(myTarget);
8
ответ дан 1 December 2019 в 19:07
поделиться

У вас есть несколько основных вариантов:

1) Укажите, какой класс будет использовать обратный вызов, чтобы типы указателя объекта и указателя функции-члена были известны и могли использоваться в звонящий. У класса может быть несколько функций-членов с одинаковой сигнатурой, из которых вы можете выбирать, но ваши возможности весьма ограничены.

Одна вещь, которую вы сделали неправильно в своем коде, заключается в том, что указатели на функции-члены и указатели на свободные функции в C ++ не совпадают и не являются совместимыми типами. Ваша функция регистрации обратного вызова принимает указатель на функцию, но вы пытаетесь передать ему указатель на функцию-член. Не допускается. Более того, тип объекта this является частью типа указателя функции-члена, поэтому в C ++ нет такой вещи, как «указатель на любую функцию-член, которая принимает целое число и возвращает void». Это должен быть «указатель на любую функцию-член Target , которая принимает целое число и возвращает void». Отсюда и ограниченные возможности.

2) Определите чистую виртуальную функцию в классе интерфейса. Следовательно, любой класс, который хочет получить обратный вызов, может быть унаследован от класса интерфейса. Благодаря множественному наследованию это не мешает остальной иерархии классов. Это почти то же самое, что определение интерфейса в Java.

3) Используйте функцию, не являющуюся членом для обратного вызова.Для каждого класса, который хочет его использовать, вы пишете небольшую функцию без заглушек, которая принимает указатель объекта и вызывает на нем нужную функцию-член. Итак, в вашем случае у вас будет:

dosomething_stub(void *obj, int a) {
    ((Target *)obj)->doSomething(a);
}

4) Используйте шаблоны:

template<typename CB> class MyClassWithCallback {
    CB *callback;
 public:
    void setCallback(CB &cb) { callback = &cb; }
    void callCallback(int a) {
        callback(a);
    }
};

class Target {
    void operator()(int a) { /* do something; */ }
};

int main() {
    Target t;
    MyClassWithCallback<T> caller;
    caller.setCallback(t);
}

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

4
ответ дан 1 December 2019 в 19:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: