Copying a vector of derived classes to a vector of base class

Hi there,

I have a vector of derived classes and I want to make a vector of base class.

From vector<DerivedClass*> to vector<BaseClass*>

How can I do this?
ambuliAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

peprCommented:
Probably the most reliable and recommended way is to use the std::copy() from <algorithms>. You should be aware that you copy only the pointers to the same objects. The objects are shared from the two vectors. This way you should think about who is the owner and who will be responsible for deleting the objects later. Try this code (C++11):
#include <algorithm>    // std::copy()
#include <iostream>     // std::cout
#include <iterator>     // std::back_inserter()
#include <string>
#include <vector>

using namespace std;

class BaseClass
{
public:
    BaseClass(int n) { m_n = n; }
    virtual string str() { return "BaseClass object " + to_string(m_n); }

protected:
    int m_n;
};


class DerivedClass : public BaseClass
{
public:
    DerivedClass(int n) : BaseClass(n) { }
    virtual string str() { return "DerivedClass object " + to_string(m_n); }
};


int main()
{
    // Vector of pointers to derived class objects.
    vector<DerivedClass*> vecD;

    for (int i = 0; i < 10; ++i)
        vecD.push_back(new DerivedClass(i));

    cout << "From vecD..." << endl;
    for (auto const p : vecD)
        cout << p->str() << endl;

    cout << string(70, '-') << endl;

    // Empty vector of pointers to base class objects.
    vector<BaseClass*> vecB;

    // Copy the pointers to the vector of pointers to base (the core of the answer).
    copy(vecD.begin(), vecD.end(), back_inserter(vecB));

    cout << "From vecB..." << endl;
    for (auto const p : vecB)
        cout << p->str() << endl;

    return 0;
}

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
evilrixSenior Software Engineer (Avast)Commented:
What's wrong with just using the constructor?

#include <vector>

struct B
{
   virtual ~B(){}
};

struct D : B
{
};

int main()
{
   auto && vD = std::vector<D *>{ new D(), new D(), new D() };
   auto && vB = std::vector<B *>(vD.begin(), vD.end());
}

Open in new window


BTW: it is a patently bad idea to use raw pointers in an STL container. It is wholly unsafe because you have to manage the lifetime of each and every item. You should consider using a smart pointer, such as std::unique_ptr or std::shared_ptr.

#include <vector>
#include <memory>

struct B
{
   virtual ~B(){}
};

struct D : B
{
};

int main()
{
   auto && vD = std::vector<std::shared_ptr<D>>{
      std::shared_ptr<D>(new D()),
      std::shared_ptr<D>(new D()),
      std::shared_ptr<D>(new D())
   };
   auto && vB = std::vector<std::shared_ptr<B>>(vD.begin(), vD.end());
}

Open in new window

1
sarabandeCommented:
it is a patently bad idea to use raw pointers in an STL container
actually, if you want to store baseclass pointers of multiple derived classes for virtual use in a container it is the only way ...

you could make the thing rather safe by using an 'all' container which contains all those baseclass pointers (or objects). then the owner of this container, typically a singleton or the baseclass itself using a static container, is solely responsible for managing (adding and removing) the pointers.

I have a vector of derived classes and I want to make a vector of base class.
From vector<DerivedClass*> to vector<BaseClass*>
if we assume that all classes were derived public from base class and the base class in question is not second within a multiple inheritance, then base class pointer and derived class pointer have same pointer value, what means that you could cast the vector from vector<DerivedClass*> to vector<BaseClass*>

std::vector<Derived*> darr;
...
std::vector<Base*> barr = (std::vector<Base*>)darr;

Open in new window


this code would work but actually it is much easier if you would not use std::vector<Derived*> at all but always std::vector<Base*> if you have the need to store pointers of multiple derived classes. or use a vector with derived objects rather than pointers. each of these objects may be used with full derived functionality and base class functionality:

std::vector<Derived> darr;
darr.push_back(Derived());
Derived & d = darr.back();
d.Base::someBaseFunction();
d.someVirtualFunction();
...
// you even could do (not recommended)
Base * pb = &darr[index];
// here the owner of barr must be absolutely aware that 
// the objects would be deleted with the destruction of darr.
std::vector<Base*> barr;
barr.push_back(pb);

Open in new window


note, if you can't make sure that there is exactly one which is responsible for the pointer and its deletion, you should use smart pointers as shown by evilrix. though smart pointers to different derived classes couldn't be put into one container, you often will see that this isn't actually necessary.

Sara
0
Ultimate Tool Kit for Technology Solution Provider

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy now.

evilrixSenior Software Engineer (Avast)Commented:
>> actually, if you want to store baseclass pointers of multiple derived classes for virtual use in a container it is the only way ...

Sorry, are you saying that you can't use a shared_ptr to represent both a derived and base class pointer to the same object?

There is absolutely no reason why you can't use two shared pointers with a shared reference count to both a base and derived object. This is perfectly safe and will completely manage ownership semantics. You do not need to re-invent the wheel by creating a singleton "all" container to manage ownership.

In other words this is perfectly safe...

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

struct B
{
   virtual ~B(){}

   virtual void foo() const = 0;
};

struct D : B
{
   void foo() const
   {
      std::cout << "D::foo()" << std::endl;
   }
};


int main()
{
   auto && vD = std::vector<std::shared_ptr<D>>{
      std::shared_ptr<D>(new D()),
      std::shared_ptr<D>(new D()),
      std::shared_ptr<D>(new D())
   };
   
   auto && vB = std::vector<std::shared_ptr<B>>(vD.begin(), vD.end());

   for(auto const & pB : vB)
   {
      pB->foo();
   }
}

Open in new window


Or, is it possible I've just misunderstood what you are asserting?
0
peprCommented:
My +1 to evilrix code -- using the vector constructor, passing the source begin(), end() iterators.

The shared_ptr is the enhancement that is orthogonal to the problem. It is one way how to solve the destruction of the objects in the vector when they are not used any more. (In my example, the objects were never destroyed, and they were released only when the runtime released the heap space used by the process -- I should have emphasize that more in my comment.
0
sarabandeCommented:
are you saying that you can't use a shared_ptr to represent both a derived and base class pointer to the same object?
no. i said that a container to store objects of different derived classes which were derived from the same base class could only be made by using base class pointers (raw pointers). i also said, that it is not really necessary to copy pointers stored in a vector when the derived pointers have the same pointer value as the base class pointers (what is normally the case if multiple inheritance is not involved).

a shared pointer solves the problem to free an object where multiple pointers to the same instance may exist. in times where we have languages with automatic garbage collection (gc), this add same comfort to older languages without a gc. however, the task also could be solved by a solid design where there is one owner which lives longer than all other who would access an object and therefore can safely free the object. granted, that such a solid design exists, it is absolutely no issue to have a container that stores base class pointers for virtual use.

Sara
0
evilrixSenior Software Engineer (Avast)Commented:
>>  could only be made by using base class pointers (raw pointers)
Okay, but they don't have to be raw pointers, they can still be shared pointers, right?

>> where there is one owner which lives longer than all other who would access an object
That's true if it is part of the natural design, but I wouldn't specifically design that as a solution since shared pointers also solve the problem and they are part of the language.

Okay, good. It seems are are more of less on the same page. I just wanted to seek clarification (a) to make sure I'd not missed something important and (b) because if I was unsure there was a good chance so the was the asker.

Thanks for taking the time to clear that up, Sarah.
0
sarabandeCommented:
Okay, but they don't have to be raw pointers, they can still be shared pointers, right?
i never tried like

std::vector< shared_ptr< Base > > somearr;

and would have thought it doesn't work for abstract base classes?

It seems we are more or less on the same page.
yes. generally pointers should be avoided and if you do so, it doesn't make so much difference whether they would have been shared pointers or not, right? function pointers and base class pointers for virtual use can make some exception to this general rule, at least when using c++ 98 standard where you have little alternatives.

Sara
0
evilrixSenior Software Engineer (Avast)Commented:
You are perfectly safe to use shared_ptr. After all, under the hood it is still just a pointer.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C++

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.