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
How to Set Timeout for Std::Cin
Struct Initialization of the C/C++ Programming Language
What's the Precedence of Comma Operator Inside Conditional Operator in C++
C++:Creating an Array with a Size Entered by the User
How Are Circular #Includes Resolved
G++ Does Not Show a 'Unused' Warning
C++ on X86-64: When Are Structs/Classes Passed and Returned in Registers
Gcc Linker Can't Find Standard Library
How to Validate Input Using Scanf
Why Is the Empty Base Class Optimization (Ebo) Is Not Working in Msvc
Behavior When Dereferencing the .End() of a Vector of Strings
C++/C Function Pointers That Return Void*
Qml and C++ Image Interoperability
Copyfileex with Progress Callback in Qt
Mesh Class Called with Default Constructor Not Working Opengl C++
Inferring the Call Signature of a Lambda or Arbitrary Callable for "Make_Function"