迭代向量和调用函数

Igo*_*Oks 4 c++ iteration foreach stl

我有一个类,其中包含另一个类对象的向量作为成员.在这个类的许多函数中,我必须对向量中的所有对象执行相同的操作:

class Small
{
  public:
    void foo(); 
    void bar(int x);
    // and many more functions
};

class Big
{
  public:
    void foo()
    {
        for (size_t i = 0; i <  VectorOfSmalls.size(); i++)
            VectorOfSmalls[i]->foo();
    }
    void bar(int x)
    {
        for (size_t i = 0; i <  VectorOfSmalls.size(); i++)
            VectorOfSmalls[i]->bar(x);
    }
    // and many more functions
  private:
    vector<Small*> VectorOfSmalls;
};
Run Code Online (Sandbox Code Playgroud)

我想简化代码,并找到一种不在每个函数中复制其他向量的方法.

我考虑过创建一个接收函数指针的函数,并在向量的每个成员上调用指向函数.但我不确定在C++中使用函数指针是一个好主意.

我也一直在考虑函子和函数,但它会强迫我为每个函数创建一个类,这听起来像是一种矫枉过正.

另一种可能的解决方案是创建一个接收字符串的函数,并根据字符串调用该命令:

void Big::call_command(const string & command)
{
    for (size_t i = 0; i <  VectorOfSmalls.size(); i++)
    {
       if (command == "foo")
           VectorOfSmalls[i]->foo();
       else if (command == "bar")
           VectorOfSmalls[i]->bar();
    }
}
void Big::foo()
{
    call_command("foo");
}
Run Code Online (Sandbox Code Playgroud)

但它可能工作缓慢(不需要创建字符串而不仅仅是函数调用),并且如果函数具有不同的签名也会产生问题.

那么你会推荐什么?我应该保留现在的一切吗?

编辑:我只能使用STL而不是boost(旧编译器).

Eva*_*ran 16

那么你可以重写for循环以使用迭代器和更多的STL,如下所示:

void foo() {
    std::for_each(VectorOfSmalls.begin(), VectorOfSmalls.end(), std::mem_fun(&Small::foo));
}

void bar() {
    std::for_each(VectorOfSmalls.begin(), VectorOfSmalls.end(), std::mem_fun(&Small::bar));
}
Run Code Online (Sandbox Code Playgroud)

除此之外,你可以使用一些宏来避免重新输入那么多,但我不是那个人的忠实粉丝.就个人而言,我喜欢使用命令字符串的单个函数.因为它为您提供了更多的决策权.

如果你选择使用一个函数来决定做什么,我会使用枚举和这样的开关,它会比字符串和级联更有效.此外,在您的示例中,您可以决定在循环内执行哪些操作.在循环外检查并拥有循环的冗余副本更有效,因为每个调用只需要决定"哪个命令".(注意:如果命令在编译时已知,则可以使命令成为模板参数,听起来就是这样).

class Big {
public:
    enum Command {
        DO_FOO,
        DO_BAR
    };

void doit(Command cmd) {
    switch(cmd) {
    case DO_FOO:
        std::for_each(VectorOfSmalls.begin(), VectorOfSmalls.end(), std::mem_fun(&Small::foo));
        break;
    case DO_BAR:
        std::for_each(VectorOfSmalls.begin(), VectorOfSmalls.end(), std::mem_fun(&Small::bar));
        break;
    }
};
Run Code Online (Sandbox Code Playgroud)

另外,正如您所提到的,替换&Small :: whatever,成员函数指针并将其作为参数传递是相当简单的.你甚至可以把它变成一个模板.

class Big {
public:
    template<void (Small::*fn)()>
    void doit() {
        std::for_each(VectorOfSmalls.begin(), VectorOfSmalls.end(), std::mem_fun(fn));
    }
};
Run Code Online (Sandbox Code Playgroud)

然后你可以这样做:

Big b;
b.doit<&Small::foo>();
b.doit<&Small::bar>();
Run Code Online (Sandbox Code Playgroud)

关于这个和常规参数方法的好处是,如果你改变小以拥有更多例程,则不需要改变Big!我认为这是首选的方法.

如果你想要能够处理单个参数,你还需要添加一个bind2nd,这是一个完整的例子:

#include <algorithm>
#include <functional>
#include <iostream>
#include <vector>

class Small {
public:
    void foo() { std::cout << "foo" << std::endl; }
    void bar(int x) { std::cout << "bar" << std::endl; }
};


class Big {
public:
    template<void (Small::*fn)()>
    void doit() {
        std::for_each(VectorOfSmalls.begin(), VectorOfSmalls.end(), std::mem_fun(fn));
    }

    template<class T, void (Small::*fn)(T)>
    void doit(T x) {
        std::for_each(VectorOfSmalls.begin(), VectorOfSmalls.end(), std::bind2nd(std::mem_fun(fn), x));
    }
public:
    std::vector<Small *> VectorOfSmalls;
};

int main() {
    Big b;
    b.VectorOfSmalls.push_back(new Small);
    b.VectorOfSmalls.push_back(new Small);

    b.doit<&Small::foo>();
    b.doit<int, &Small::bar>(5);
}
Run Code Online (Sandbox Code Playgroud)