Ну, вы можете переписать циклы 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));
}
Кроме того, вы можете использовать некоторые макросы, чтобы избежать повторного набора, но я не большой поклонник этого. Лично мне нравятся несколько функций над одной, которая принимает командную строку. Так как это дает вам больше гибкости в отношении того, как принимается решение.
Если вы используете одну функцию, принимающую параметр, чтобы решить, что делать, я бы использовал перечисление и переключатель, подобные этому, это было бы более эффективно, чем строки и каскад, если. Кроме того, в вашем примере у вас есть if, чтобы решить, что делать внутри цикла. Более эффективно выполнять проверку вне цикла и иметь избыточные копии цикла, поскольку «какую команду» нужно решать только один раз за вызов. (ПРИМЕЧАНИЕ: вы можете сделать команду параметром шаблона, если он известен во время компиляции, что звучит так, как оно есть).
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;
}
};
Кроме того, как вы упомянули, довольно просто заменить & Small :: что угодно, что является указателем на функцию-член, и просто передать его в качестве параметра. Вы даже можете сделать это шаблоном.
class Big {
public:
template<void (Small::*fn)()>
void doit() {
std::for_each(VectorOfSmalls.begin(), VectorOfSmalls.end(), std::mem_fun(fn));
}
};
Тогда вы можете сделать:
Big b;
b.doit<&Small::foo>();
b.doit<&Small::bar>();
Хорошая вещь и в этом, и в методах обычных параметров заключается в том, что Big не нужно изменять, если вы измените small, чтобы иметь больше подпрограмм! Я думаю, что это предпочтительный метод.
Если вы хотите иметь возможность обрабатывать один параметр, вам также нужно добавить 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);
}