题
我有一个类,其中包含另一个类对象的向量作为成员。在此类的许多函数中,我必须对向量中的所有对象执行相同的操作:
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;
};
我想简化代码,并找到一种方法,不要在每个函数中重复其他向量。
我考虑过创建一个函数,该函数接收指向函数的指针,并在向量的每个成员上调用指向的函数。但我不确定在 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");
}
但它可能运行缓慢(不需要创建字符串而不仅仅是函数调用),并且如果函数具有不同的签名也会产生问题。
那么你会推荐什么?我应该让一切保持现在的样子吗?
编辑:我只能使用 STL 而不能使用 boost(旧编译器)。
解决方案
那么你可以重写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));
}
除此之外,你可以使用一些宏来避免重新输入了很多,但我不是这方面的一个巨大的风扇。就个人而言,我很喜欢在单一个它接受一个命令串的多重功能。由于它可以让你的决定是如何做出更多的功能。
如果你做一个单一功能去拍摄参数去决定哪些做的,我会用一个枚举和这样一个开关,它会比弦更有效,如果一个级联。此外,在您的例子中,你有,如果决定要在循环中做。这是更有效的循环外检查,并有循环冗余副本,因为“该命令”只需要调用每一次决定。 (注:可以使命令模板参数,如果它是在编译时,它听起来像它是已知的)。
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;
}
};
此外,正如你所说,这是相当琐碎,以取代与小::什么,有什么成员函数指针,只是传递作为参数。你甚至可以把它的模板了。
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>();
这件事,定时参数方法两个好处是,大的并不需要改变,如果你改变小有更多的程序!我认为这是优选的方法。
如果您希望能够处理一个单一的参数,你就需要添加一个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);
}
其他提示
如果您使用的STD库,你应该看看的for_each
您提到,在C ++中使用函数指针可能不是一个好主意,但 - 让你担心的是速度 - 你必须看到,如果这是一个即使你在,担心之前的性能瓶颈区域。 p>