C++: Can Vector<Base> Contain Objects of Type Derived

c++: can vector Base contain objects of type Derived?

No, the Derived objects will be sliced: all additional members will be discarded.

Instead of raw pointers, use std::vector<std::unique_ptr<Base> >.

Vector of pointers to base class containing base and derived class objects - accessing derived-class specific variables

Yes it is possible. You only need to cast the pointer. The simplest syntax is:

((Derived*)e)->DerviedVariable

which is equivalent (modulo casting away constness, if any) to C++ish

static_cast<Derived*>(e)->DerviedVariable

The word “static” here reminds that there is no runtime checking: the compiler trusts you that e indeed points to an instance of Derived. If it doesn’t, undefined behavior occurs. The safer alternative is dynamic_cast:

Derived *ee = dynamic_cast<Derived*>(e);
if (ee)
x = ee->DerviedVariable;

It returns NULL if the object is not an instance of Derived. (Note that references can be casted as well, but as there is no NULL reference, dynamic_cast will throw instead if cast is not possible)

Nevertheless, using such casts is often considered a bad practice, for a reason. Virtual functions are preferable, mostly because using them don’t require you to even know the actual object type at the call point.

Store derived class objects in base class variables

What you are seeing is Object Slicing.

You are storing object of Derived class in an vector which is supposed to store objects of Base class, this leads to Object slicing and the derived class specific members of the object being stored get sliced off, thus the object stored in the vector just acts as object of Base class.

Solution:

You should store pointer to object of Base class in the vector:

vector<Base*> 

By storing a pointer to Base class there would be no slicing and you can achieve the desired polymorphic behavior as well.

Since you ask for a C++ish way of doing this, the right approach is to use a suitable Smart pointer instead of storing a raw pointer in the vector. That will ensure you do not have to manually manage the memory, RAII will do that for you automatically.

How can I create a vector of derived objects?

First of all, you're missing a base class. Column is a template, not a class, and having virtual methods inside a template is rarely useful.

class Column {
public:
Column();
virtual ~Column() {}
std::string getName() const { return _name; }
virtual std::string getType();

protected:
std::string _name;
};

template <typename T> class ColumnImpl : public Column {
public:
ColumnImpl();
std::vector<T>& getData() { return _data; }
std::vector<T> const& getData() const { return _data; }

protected:
std::vector<T> _data;
};

Now you can do

std::vector<std::unique_ptr<Column>> vec;

to store (owning) pointers to Column instances.

Getting a vector Derived* into a function that expects a vector Base*

vector<Base*> and vector<Derived*> are unrelated types, so you can't do this. This is explained in the C++ FAQ here.

You need to change your variable from a vector<Derived*> to a vector<Base*> and insert Derived objects into it.

Also, to avoid copying the vector unnecessarily, you should pass it by const-reference, not by value:

void BaseFoo( const std::vector<Base*>& vec )
{
...
}

Finally, to avoid memory leaks, and make your code exception-safe, consider using a container designed to handle heap-allocated objects, e.g:

#include <boost/ptr_container/ptr_vector.hpp>
boost::ptr_vector<Base> vec;

Alternatively, change the vector to hold a smart pointer instead of using raw pointers:

#include <memory>
std::vector< std::shared_ptr<Base*> > vec;

or

#include <boost/shared_ptr.hpp>
std::vector< boost::shared_ptr<Base*> > vec;

In each case, you would need to modify your BaseFoo function accordingly.

Storing derived objects in a vector by base class, and upon removal return them to derived objects

By the feedback provided in the comments, I would go with a solution like this:

class Card {
private:
CardKind kind_;
std::fucntion<void (Card &)> attack_;
std::function<void (Card &)> effectFunc_;

std::unordered_map<std::string, boost::any> properties;

Card(CardKind kind, std::function<void (Card &)> attackFunc,
std::function<void (Card &)> effectFunc);
};

Base and derived objects held in vector of base class type get sliced

There is no slicing in your code. You forgot to declare Base::display as virtual, hence calling display on a Base* will call Base::display.

class Base
{
protected:
string baseVariable_;
public:
virtual void display() {
// ^^----------------------------------------------- !!!
cout << "BaseVar: " << baseVariable_ << endl;
}
friend istream& operator>>(istream& in, Base& obj);
virtual ~Base() {}
};

And for polymorphic types you need to add a virtual destructor too.



Related Topics



Leave a reply



Submit