2

I have a class which contains pure virtual functions. I am using this class to make sure I do not forget to implement some methods in derived classes.

I have a collection of derived classes like

class B : public A
class C : public A
class D : public A 
etc

How can I create a container that can hold all of these derived classes (B,C,D)? I would prefer to use a standard container such as vector. I tried creating a vector of the base class but this results in the derived classes being converted if they are pushed onto the vector leading to a compilation error of invalid new-expression of abstract class type.

My base class:

class A
{
public:
    A();
    virtual ~A();

    virtual double GetVolume() = 0;
};

Example derived class:

class B : public A
{
public:
    B(){};
    virtual ~B(){};

    double GetVolume(){};
};
Adam
  • 177
  • 1
  • 8
  • @πάνταῥεῖ I dont think this is an appropriate dupe, the answer here is not likely going to be a `boost::any` type, but a factory method and storing a `std::shared_ptr` to `A` ... – Fantastic Mr Fox Sep 26 '16 at 18:03
  • @Ben Vote to reopen then. – πάντα ῥεῖ Sep 26 '16 at 18:04
  • Maybe closer to this: http://stackoverflow.com/questions/11895163/c-vector-storing-base-class-pointers, but not really ... – Fantastic Mr Fox Sep 26 '16 at 18:05
  • It's probably a duplicate of *something*, but that is not the correct duplicate, for sure. In this question you have an inheritance hierarchy, in the linked question they are three unrelated types. Now this user is going to use variant/any instead of simple polymorphism... IMHO this is actively misleading and a disservice to the user. – Nir Friedman Sep 26 '16 at 18:06
  • 1
    How about this one instead: http://stackoverflow.com/questions/34383979/c-vector-of-base-class-objects – Nir Friedman Sep 26 '16 at 18:09
  • Use a vector of pointers rather than objects. – Barmar Sep 26 '16 at 18:15
  • I think `std::vector>` is probably what you need - storing pointers allows virtual dispatch and prevents object slicing. – Galik Sep 26 '16 at 18:16

1 Answers1

4

You need to create a container of pointer-to-base. A container of base objects causes conversion from derived to base, which is called slicing. When you have a pointer-to-base however, the object can still have a different type (a derived one) than the base class, this is called the dynamic type of the object (as opposed to static type).

In modern C++ it's best to use smart pointers for this:

std::vector<std::unique_ptr<A>> x;
x.push_back(std::make_unique<B>());
x.push_back(std::make_unique<C>());
x.push_back(std::make_unique<D>());

for (auto& e : x) {
    e->GetVolume();
}
Nir Friedman
  • 17,108
  • 2
  • 44
  • 72
  • would it be better to use emplace_back vs push_back? – Adam Sep 26 '16 at 21:01
  • @Adam It doesn't make too much difference in a situation like this. Because unique_ptr is so trivial and cheap to move, performance won't matter much, and anyway calling push_back without reserve is not going to have great performance. If I already have the object or something implicitly convertible to the object, I generally prefer push_back to emplace_back where perf isn't an issue. The function signature is much simpler; you get better error messages if you mess up and better help from the IDE. – Nir Friedman Sep 26 '16 at 21:09