2015-04-15 39 views
4

如果我有:如何循环异构类的实例来调用具有相同名称和参数的方法?

class A { 
    void foo(); 
}; 

class B { 
    void foo(); 
}; 

有没有办法来收集A类型和B的情况下,对他们的循环调用foo()方法?例如使用一些宏或指针和一些特殊的数据类型?或者收集函数指针?

下面的伪代码可能会给出我的意思。

int main() { 
    A a; 
    B b; 

    hypothetical_container_t hypothetical_container; 
    hypothetical_container.push_back(a); 
    hypothetical_container.push_back(b); 

    [...]//Do stuff with a, do other stuff with b 

    for (hypothetical_container_t::iterator ii = hypothetical_container.begin(); ii != hypothetical_container.end(); ++ii) { 
     ii->foo(); 
    } 
} 

用例是具有一串boost::shared_ptr变量具有不同类型T的并调用所有这些.reset()。 (我知道在这个例子中调用重置将不是必需的)。

+0

boost :: variant? – user1937198

+0

也许尝试functor? – Jiang

+0

编译时已知类型吗?如果是这样,你可以使用一个元组作为容器,并迭代一个可变模板。如果不是,则需要在公共基类中使用虚函数。 –

回答

3

如果你有改变的类A和B的选择,我会建议与answer by @mstbaum去。

如果您没有该选项,我有以下建议。

#include <memory> 
#include <iostream> 
#include <vector> 

struct A { 
    void foo(){} 
}; 

struct B { 
    void foo(){} 
}; 

struct Wrapper 
{ 
    virtual void foo() = 0; 
}; 

template <typename T> struct WrapperImpl : Wrapper 
{ 
    WrapperImpl(T& obj) : obj_(obj) {} 
    void foo() {obj_.foo();} 
    T& obj_; 
}; 

template <typename T> 
std::unique_ptr<Wrapper> makeWrapper(T& t) 
{ 
    return std::unique_ptr<Wrapper>(new WrapperImpl<T>(t)); 
} 

int main() 
{ 
    std::vector<std::unique_ptr<Wrapper>> v; 
    A a; 
    B b; 
    v.push_back(makeWrapper(a)); 
    v.push_back(makeWrapper(b)); 

    for (auto& item : v) 
    { 
     item->foo(); 
    } 
} 
+1

仍然有一些C++ 11功能被使用(但我认为没有什么东西禁止使用boost :: shared_ptr来代替'std :: unique_ptr',for循环只是一个问题。改写),但你的解决方案看起来相当惊人! – Antonio

+0

@Antonio,我很高兴我的建议对你有用。 –

2

您应该能够使用虚拟类:

virtual class C { 
    public: 
     virtual void foo() = 0; 
} 

class A : public C { 
    virtual void foo(); 
}; 

class B : public C { 
    virtual void foo(); 
}; 

然后在主,你可以有:

A a; 
B b; 

std::vector<C*> vec; 
vec.push_back(&a); 
vec.push_back(&b); 

然后你可以遍历并调用foo的方法,它的所有成员矢量保证实现。

WRT的boost :: shared_ptr的,我没有那么熟悉,但我想你可以这样做:

boost::shared_ptr<C> a(new A); 
boost::shared_ptr<C> b(new B); 

std::vector<boost::shared_ptr<C>> vec; 
+2

你需要存储指针。 'push_back(a)'将尝试通过切分'a'来创建'C'对象。幸运的是,这会给出一个友好的编译时错误,而不是模糊的运行时问题,因为'C'是抽象的。 –

+0

好点,我将编辑 – mstbaum

+0

这不适用于'boost :: shared_ptr' ... – Antonio

1

我怎么能在异构类的实例周期调用方法 与相同的名称和参数?

这需要模板!

#include <memory> 
#include <iostream> 

void chain_call_reset() 
{ 
} 

template<typename Arg, typename ... Rest> 
void chain_call_reset(Arg&& arg, Rest&&... rest) 
{ 
    arg.reset(); 
    chain_call_reset(rest...); 
} 

int  main() 
{ 
    std::shared_ptr<int> ptr = std::make_shared<int>(42); 
    std::shared_ptr<char> ptr2 = std::make_shared<char>('c'); 
    std::shared_ptr<float> ptr3 = std::make_shared<float>(4.2); 

    chain_call_reset(ptr, ptr2, ptr3); 

    std::cout << std::boolalpha << !!ptr << std::endl; 
    std::cout << std::boolalpha << !!ptr2 << std::endl; 
    std::cout << std::boolalpha << !!ptr3 << std::endl; 
} 

但如果是你的类型之间没有共同的层次结构,模板是要走的路:)

+0

我很感谢你的回答。然而,我无法使用可变参数模板,太糟糕了...... – Antonio

+0

@Antonio模拟此功能的提升方式是为函数重载一个足够合理的参数数量(比如10,15或20),这在大多数情况下应该足够了:) – Drax

1

您的任务需要键入elision。 Boost :: any就是一个很好的例子。 一个简单的一个用于调用公共功能:

#include <iostream> 
#include <memory> 
#include <vector> 

class Any 
{ 
    // Content 
    // ======= 

    private: 
    class ContentInterface 
    { 
     public: 
     virtual ~ContentInterface() {} 
     virtual void call() const {} 
    }; 

    template <typename T> 
    class Content : public ContentInterface 
    { 
     private: 
     T& m_object; 

     public: 
     Content(T& object) 
     : m_object(object) 
     {} 

     virtual void call() const { m_object.foo(); } 
    }; 

    // use boost here:  
    typedef std::shared_ptr<ContentInterface> content_ptr; 

    // Constructionn 
    // ============= 

    public: 
    Any() 
    {} 

    template<typename T> 
    Any(T& object) 
    : m_content(new Content<T>(object)) 
    {} 

    void call() const { m_content->call(); } 

    private: 
    content_ptr m_content; 
}; 

struct A { 
    void foo() { std::cout << "A\n"; } 
}; 

struct B { 
    void foo() { std::cout << "B\n"; } 
}; 

int main(void) 
{ 
    typedef std::vector<Any> container; 
    A a; 
    B b; 
    container v; 
    v.push_back(a); 
    v.push_back(b); 
    for(container::const_iterator pos = v.begin(); pos != v.end(); ++pos) 
     pos->call(); 
} 

另一种方法是标准::函数的std ::绑定(再次,使用升压功能,在C++ 98):

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

int main() 
{ 
    typedef std::function<void()> function; 
    typedef std::vector<function> container; 
    A a; 
    B b; 
    container v; 

    v.push_back(std::bind(&A::foo, a)); 
    v.push_back(std::bind(&B::foo, b)); 
    for(container::const_iterator pos = v.begin(); pos != v.end(); ++pos) 
     (*pos)(); 
} 
0

如果您无法访问可变模板,您可以使用boost::fusion

#include <iostream> 

#include <boost/shared_ptr.hpp> 
#include <boost/make_shared.hpp> 
#include <boost/fusion/include/make_vector.hpp> 
#include <boost/fusion/include/for_each.hpp> 

struct reset 
{ 
    template<typename T> 
    void operator()(T& t) const 
    { 
    t.reset(); 
    } 
}; 

int  main() 
{ 
    boost::shared_ptr<int> ptr = boost::make_shared<int>(42); 
    boost::shared_ptr<char> ptr2 = boost::make_shared<char>('c'); 
    boost::shared_ptr<float> ptr3 = boost::make_shared<float>(4.2); 


    boost::fusion::vector<boost::shared_ptr<int>&, boost::shared_ptr<char>&, boost::shared_ptr<float>& > vec 
    = boost::fusion::make_vector(boost::ref(ptr), boost::ref(ptr2), boost::ref(ptr3)); 

    boost::fusion::for_each(vec, reset()); 

    std::cout << std::boolalpha << !!ptr << std::endl; 
    std::cout << std::boolalpha << !!ptr2 << std::endl; 
    std::cout << std::boolalpha << !!ptr3 << std::endl; 
} 
相关问题