【问题标题】:C++: How do I pass a container of derived classes to a function expecting a container of their base classes?C++:如何将派生类的容器传递给期望其基类容器的函数?
【发布时间】:2010-03-04 01:36:12
【问题描述】:

嗨!任何人都知道如何使下面代码中的“chug(derlist);”行工作?

#include <iostream>
#include <list>
using namespace std;

class Base
{
public:
    virtual void chug() { cout << "Base chug\n"; }
};

class Derived : public Base
{
public:
    virtual void chug() { cout << "Derived chug\n"; }
    void foo() { cout << "Derived foo\n"; }
};

void chug(list<Base*>& alist)
{
    for (list<Base*>::iterator i = alist.begin(), z = alist.end(); i != z; ++i)
        (*i)->chug();
}

int main() 
{
    list<Base*> baselist;
    list<Derived*> derlist;

    baselist.push_back(new Base);
    baselist.push_back(new Base);
    derlist.push_back(new Derived);
    derlist.push_back(new Derived);

    chug(baselist);
    // chug(derlist);  // How do I make this work?

    return 0;
}

我需要这个的原因基本上是,我有一个包含非常复杂对象的容器,我需要将它传递给某些函数,这些函数只关心那些复杂对象中的一两个虚函数。

我知道简短的回答是“你不能”,我真的在寻找人们用来解决这个问题的任何技巧/习语。

提前致谢。

【问题讨论】:

    标签: c++ stl polymorphism containers


    【解决方案1】:

    你的问题很奇怪;主题问“我如何在不丢失多态性的情况下将物品放入容器中” - 但这是在回避问题;容器中的项目不会丢失多态性。你只有一个基本类型的容器,一切正常。

    从您的示例看来,您要问的是“如何将子指针容器转换为基指针容器?” - 答案是,你不能。子指针可以转换为基指针,子指针的容器不能。它们是不相关的类型。虽然,请注意 shared_ptr 可以转换为 shared_ptr,但这仅仅是因为它们具有额外的魔力来实现这一目标。容器没有这种魔力。

    一个答案是让 chug 成为一个模板函数(免责声明:我没有在带有编译器的计算机上,所以我没有尝试编译它):

    template<typename C, typename T>
    void chug(const C<T>& container)
    {
        typedef typename C<T>::iterator iter;
        for(iter i = container.begin(); i < container.end(); ++i)
        {
            (*i)->chug();
        }
    }
    

    那么 chug 可以接受任何类型的任何容器,只要它是一个指针容器并且有一个 chug 方法。

    【讨论】:

    • 嗨,特里,我改写了我的问题以更准确。我同意你的想法——下面是编译 template void chug(list& alist) { for (list::iterator i = alist.begin(), z = alist.end(); i != z; ++i) (*i)->chug();它的工作原理。这不是一个完美的解决方案,因为它不是多态性,但它可以满足我的需要。我想不出任何其他不需要从 Base 派生的人编写额外代码的解决方案。
    【解决方案2】:

    要么通过指针存储它们(boost::shared_ptr 是一个流行的选项),要么使用 Boost ptr_containers 在内部存储指针,但在外部提供一个很好的 API(当然还有全自动删除)。

    #include <boost/ptr_container/ptr_vector.hpp>
    
    boost::ptr_vector<FooBase> foos;
    foos.push_back(new FooDerived(...));
    foos[0].memberFunc();
    

    容器的多态转换是不可能的,所以总是传递一个 ptr_vector& 并在函数本身中向下转换。

    【讨论】:

      【解决方案3】:

      为什么不让 chug 成为一个基于模板的函数,这样它就可以拥有基类型和派生类型的实例?

      或者,为了更好的解决方案,您可以使用std::for_each

      【讨论】:

        【解决方案4】:

        也许你可以让chug 成为一个模板函数,将模板参数转换为Base* 类型,然后在上面调用chug

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-08-20
          • 2014-04-28
          • 2012-03-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-07-11
          相关资源
          最近更新 更多