Списки функций указателя члена - PullRequest
2 голосов
/ 15 сентября 2010

Скажем, у меня есть класс:

class A
{
public:
  void doSomething();
}

Где doSomething делает что-то, что явно зависит от внутреннего состояния экземпляра A.

Теперь у меня есть ситуация, когда у меня естьвокруг куча вещей типа А, но я хочу вызывать doSomething только из их строгого подмножества, поэтому я хочу поместить их в список.В частности, я действительно хочу прикрепить указатели на отдельные doSomethings () в списке.

Могу ли я это сделать? Могу ли я объявить это следующим образом:

std::list<(A::*)()> aDoSomethings;

Я прочитал эту запись , это имеет смысл, и я пойду по этому пути, если потребуется.

Ответы [ 6 ]

3 голосов
/ 15 сентября 2010

Рассматривали ли вы простой ОО подход:

struct Can_Do_Something
{
    virtual void doSomething() = 0;
};

class A : public Can_Do_Something
{
    ...
};

std::list<Can_Do_Something*> my_list;

my_list[n]->doSomething();

Это ограничивающий доступ к той части интерфейса A, унаследованной через тип Can_Do_Something, к которой вы планируете получить доступ через список. Он документирует и применяет это ограничение.

Если вы предпочитаете что-то более близкое к вашему первоначальному видению, подумайте ...

#include <iostream>
#include <vector>
#include <boost/function.hpp>

struct A
{
    A(int n) : n_(n) { }

    int f(int x) { std::cout << "A::f() this " << (void*)this
                           << ", n_ " << n_
                           << ", x_ " << x << '\n'; }

    int n_;
};

int main()
{
    typedef boost::function<int (int n)> Function;
    typedef std::vector<Function> Functions;

    Functions functions;
    A a1(1), a2(2), a3(3);

    functions.push_back(std::bind1st(std::mem_fun(&A::f), &a1));
    functions.push_back(std::bind1st(std::mem_fun(&A::f), &a2));
    functions.push_back(std::bind1st(std::mem_fun(&A::f), &a3));

    for (Functions::iterator i = functions.begin();
            i != functions.end();
            ++i)
        (*i)(42);
}

Здесь boost :: function используется для создания обратного вызова для определенных функций, которые вас интересуют.

2 голосов
/ 15 сентября 2010

Кажется, вы не понимаете, как работают указатели на функции-члены.Для данного класса существует только один экземпляр любой данной функции.Они отличаются использованием неявного параметра this.По сути, вы можете притвориться, что у вас есть следующее отображение:

struct Struct { void Function(); }
Struct a;
a.Function();

превращается в

struct Struct { }
void Function(Struct* this);
Struct a;
Function(&a);

Так что если у вас есть набор Struct объектов, и вы хотите вызвать Function на небольшом наборе из них вы не сохраняете Function, вы храните Struct.

Указатели на функции-члены используются, когда у вас есть несколько функций, которые вы хотитезвонить выборочно.Так что если в вашем классе есть две функции, каждая из которых не принимает параметров и возвращает void, void (Struct::*)() может указывать на любую из них.Но это все же указывает на конкретную функцию, из которой есть только одна.Вам по-прежнему необходимо предоставить параметр this.

struct Struct {
  Struct(int v) : value(v) { }
  void One() { cout << "one: " << value << endl; }
  void Two() { cout << "two: " << value << endl; }
  int value;
};

int main()
{
  std::vector<Struct> v;
  v.push_back(1);
  v.push_back(2);
  v.push_back(3);

  std::vector<void (Struct::*)()> f;
  f.push_back(&Struct::One);
  f.push_back(&Struct::Two);
  f.push_back(&Struct::One);

  for(int i = 0; i < 3; ++i)
    (v[i].*f[i])();
}  

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

* edit: Пример без использования контейнеров

Struct a(5), b(10);
void (Struct::*one)() = &Struct::One;
void (Struct::*two)() = &Struct::Two;

(a.*one)();
(b.*one)();
(a.*two)();
(b.*two)();

Обратите внимание на дополнительные скобки.a.*one() недостаточно.

1 голос
/ 15 сентября 2010

Вы должны проверить boost :: function и boost :: bind.

1 голос
/ 15 сентября 2010

Указатель на функцию-член не имеет указателя на конкретный экземпляр: он описывает, как вызвать функцию-член с определенной сигнатурой с указателем и параметрами this.

Вместо этого поместите указатели на объекты, которые вам нужны, в список, а затем выполните итерацию по этому списку, вызывая doSomething для каждого элемента.

0 голосов
/ 15 сентября 2010

Если я правильно понимаю, вы хотите иметь список указателей на функции-члены, которые должны быть doSomething ()?

Тогда вы можете иметь список указателей на функции для члена вашего класса, но вам нужно будет предоставить связанный объект с ним, так почему бы просто не сохранить список (указателей) на объекты?

0 голосов
/ 15 сентября 2010

Да, вы, вероятно, хотите что-то вроде:

#include <vector>
#include <iostream>
#include <string>

using namespace std;

class A {
  string m_name;

  public:
    A(const string& name) : m_name(name) {} 
    void doSomething() { cout << m_name << "::doSomething()" << endl; }
};

int main(void) {
  A f1("f1");
  A f2("f2");
  A f3("f3");
  A f4("f4");
  vector<A*> foo_list;
  foo_list.push_back(&f1);
  foo_list.push_back(&f3);

  for (vector<A*>::iterator it = foo_list.begin(); it != foo_list.end(); *it++) {
    static_cast<A*>(*it)->doSomething();
  }

  return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...