C++: How do I pass a container of derived classes to a function expecting a container of their base classes?

老子叫甜甜 提交于 2019-12-18 07:06:47

问题


HI! Anyone know how I can make the line "chug(derlist);" in the code below work?

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

The reason I need this is basically, I have a container of very complex objects, which I need to pass to certain functions that only care about one or two virtual functions in those complex objects.

I know the short answer is "you can't," I'm really looking for any tricks/idioms that people use to get around this problem.

Thanks in advance.


回答1:


Your question is odd; the subject asks "how do I put items in a container without losing polymorphism" - but that is begging the question; items in containers do not lose polymorphism. You just have a container of the base type and everything works.

From your sample, it looks what you're asking is "how do I convert a container of child pointers to a container of base pointers?" - and the answer to that is, you can't. child pointers are convertible to base pointers, containers of child pointers are not. They are unrelated types. Although, note that a shared_ptr is convertible to shared_ptr, but only because they have extra magic to make that work. The containers have no such magic.

One answer would be to make chug a template function (disclaimer: I'm not on a computer with a compiler, so I haven't tried compiling this):

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

Then chug can take any container of any type, as long as it's a container of pointers and has a chug method.




回答2:


Either store them by pointer (boost::shared_ptr is a popular option), or use Boost ptr_containers that store pointers internally, but offer a nice API on the outside (and of course fully automated deletion).

#include <boost/ptr_container/ptr_vector.hpp>

boost::ptr_vector<FooBase> foos;
foos.push_back(new FooDerived(...));
foos[0].memberFunc();

Polymorphic conversions of containers are simply not possible, so always pass a ptr_vector<Base>& and downcast in the function itself.




回答3:


Why not make chug a template based function so it can have instances for base and derived types?

Or, for a better solution you can use std::for_each.




回答4:


Maybe you can make chug a template function that casts the template parameter to a Base* type, then calls chug on that.



来源:https://stackoverflow.com/questions/2376334/c-how-do-i-pass-a-container-of-derived-classes-to-a-function-expecting-a-cont

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!