2009-01-19 54 views
4

我有一个类有另一个类对象的向量作为成员。在这个类的很多功能我必须做对Vector中的所有对象相同的操作:遍历矢量和调用函数

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++中使用函数指针是个好主意。

我也一直在考虑仿函数和functionoids,但它会迫使我为每个函数创建一个类,它听起来像是一种矫枉过正。

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

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而不是提升(旧编译器)。

回答

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)); 
} 

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

如果你确实需要一个参数来决定该怎么做,我会使用一个枚举和一个像这样的开关,它比字符串和级联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; 
    } 
}; 

而且,正如你所说,这是相当琐碎,以取代&小::什么,有什么成员函数指针,只是传递作为参数。你甚至可以把它做成一个模板。

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); 
} 
+0

谢谢埃文。但std :: mem_fn是boost的一部分,而不是STL。也许有另一种方法来使用for_each在我的情况?那么具有不同签名的功能呢? – 2009-01-19 19:07:44

+0

oops,typo:mem_fn是boost的一部分,但std :: mem_fun是STL的一部分。 – 2009-01-19 20:26:49

4

如果你使用std库,你应该看看for_each

您提到在C++中使用函数指针可能不是一个好主意,但是 - 让您担心的是速度 - 您必须在担心之前查看它是否甚至是性能瓶颈区域。

0

尝试boost::functionboost::bind

void Big::call_command(const boost::function<void (Small*)>& f) 
{ 
    for (size_t i = 0; i < VectorOfSmalls.size(); i++) 
    { 
     f(VectorOfSmalls[i]); 
    } 
} 

int main() 
{ 
    Big b; 
    b.call_command(boost::bind(&Small::foo, _1)); 
    b.call_command(boost::bind(&Small::bar, _1, 5)); 
}