Search code examples
c++polymorphismpure-virtual

C++ Collection of instances implementing a pure virtual class


I am working in cross platform C++, and have some classes defined like so: (heavily simplified for this example)

class ExampleBase
{
public:
    ExampleBase( int blah ) : blah_test(blah) { }

    virtual void DoSomething( ) = 0;
private:
    int blah_test;
};

class ExampleImplementer : public ExampleBase
{
public:
    ExampleImplementer( ) : ExampleBase( 5 ) { }

    virtual void DoSomething( ) { /* unique implementation here */ }
};

Originally I had only a single class, which I stored a bunch of instances of in a std::vector and passed around by const reference. But now I need to have a base class (that I want to keep pure virtual) and a number of polymorphic implementing classes.

What is the best way to have a collection of any implementing instances, and still have leak free easy memory management like having a stack allocated std::vector?

  • Obviously I can't have a std::vector< ExampleBase > now, since std::vector requires the class to be non-pure virtual (since it does internal allocation/copying etc.). I don't want users of my code to accidentally create instances of ExampleBase because that is wrong. I also want to steer clear from any possibilities of object slicing or any other nasties.

  • An array of std::auto_ptr would do the job, but then I have to deal with initializing them all, looking for a "free slot", no iterators etc. It seems a bit crazy to do all of this wheel re-inventing.

  • boost::ptr_vector looked promising, however it behaves a little weirdly in that when building on Linux it needs ExampleBase to be non-pure virtual - and I don't understand why... So boost::ptr_vector is out.

This seems to be a simple, and probably really common situation. So what is the best way to do this? I am open to any other std or boost way of doing this: whichever is "best".


Solution

  • boost::ptr_vector is the way to go if you can have Boost. It should work for your scenario - if it does not, then something else is wrong, so please post the error message.

    Alternatively, you can go for std::vector< boost::shared_ptr<ExampleBase> >. This is less ideal, because that refcounting will add some overhead, especially when vector is resized, but otherwise a working solution.

    If your implementation supports TR1 (latest versions of g++ and MSVC), then you can use std::tr1::shared_ptr instead. This can actually be superior, because STL implementation is free to optimize based on some inner knowledge - for example, in MSVC, std::vector knows that it can use swap instead of copy constructor for std::tr1::shared_ptr, and does just that, avoiding constant refcount changes.