2

假设我有一堂课:

class A
{
public:
  void doSomething();
}

doSomething 所做的事情明确依赖于 A 实例的内部状态。

现在,我遇到了一种情况,我有一堆 A 类型的东西,但我只想从它们的严格子集中调用 doSomething,所以我想把它们放在列表中。特别是,我真正想做的是将指针指向列表中的单个 doSomethings() 。

我可以做吗? 我是否像这样声明它:

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

我读了这篇文章,这是有道理的,如果需要,我会走那条路。

4

6 回答 6

3

您是否考虑过简单的 OO 方法:

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 用于创建对您感兴趣的特定函数的回调。

于 2010-09-15T18:29:27.120 回答
2

您似乎对成员函数指针的工作方式感到困惑。对于给定的类,任何给定函数只有一个实例。它们通过使用隐式参数来区分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])();
}  

不是最好的例子,但它明白了这一点。您可以使用成员函数混合和匹配对象。

*编辑:一个没有容器妨碍的例子

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()是不够的。

于 2010-09-15T19:27:50.277 回答
1

成员函数指针没有指向特定实例的指针:它描述了如何在给定this指针和参数的情况下调用具有特定签名的成员函数。

相反,将指向您关心的对象的指针放入列表中,然后遍历该列表,调用doSomething每个项目。

于 2010-09-15T18:30:17.873 回答
1

你应该检查 boost::function 和 boost::bind。

于 2010-09-15T18:35:50.000 回答
0

是的,你可能想要这样的东西:

#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;
}
于 2010-09-15T18:28:55.507 回答
0

如果我的理解是正确的,你想要一个指向必须是 doSomething() 的函数成员的指针列表?

然后你可以有一个指向你的类成员的函数指针列表,但是你需要提供与之关联的对象,那么为什么不简单地保留一个(指向)对象的列表呢?

于 2010-09-15T18:29:18.917 回答