Reputation: 6240
I have a base structure FooBase
:
struct FooBase { };
Then I create a template structure Foo
which is a child of FooBase
:
template <typename typeName> struct Foo : public FooBase { typeName* foo };
In some class I create a vector of FooBase
and add instances of Foo
in it:
vector <FooBase> FooVector
...
Foo <Bar> fooInstance;
fooInstance.foo = new Bar();
FooVector.push_back ( fooInstance );
Then I needed to access the stored data, but I'm getting predictable and obvious error about an absence of the member foo
in FooBase
FooVector[0].foo
I can not write something like
Foo <Bar> fooInstance = FooVector[0]
since I don't know the template parameter.
How do I store instances of Foo
in the vector so I can access them later. Note, that I don't know the template parameter at the last step - when reading data from the vector.
P.S. NO BOOST ALLOWED!
Upvotes: 0
Views: 436
Reputation: 227468
You are slicing here:
vector <FooBase> FooVector
...
Foo <Bar> fooInstance;
fooInstance.foo = new Bar();
FooVector.push_back ( fooInstance );
You are pushing a Foo<Bar>
into a vector of FooBase
so you only get a FooBase
object stored. This
FooVector[0]
returns a reference to a FooBase
which knows nothing about Foo<Bar>
. You could store Foo<Bar>
directly:
vector<Foo<Bar>> FooVector;
or store pointers or smart pointers to FooBase
, but then you will have to dynamic_cast the elements to Foo<Bar>*
anyway, which isn't a very nice solution.
Upvotes: 1
Reputation: 8290
As mentioned in previous answers, you are slicing Bar into FooBase objects. Your vector has to store references to Foo objects rather than the object itself.
The easiest way to accomplish this is to use one of the smart_ptr types from the boost library.
#include <boost/shared_ptr.hpp>
#include <vector>
typedef std::vector< boost::shared_ptr<FooBase> > FooVector;
...
FooVector v;
v.push_back( new Bar() );
If you store the pointer itself into the vector you'll have problems with memory management, using the boost shared_ptr type will handle allocation for you automatically.
Upvotes: 0
Reputation: 34636
What happens here, is that in your
FooVector.push_back ( fooInstance );
line, C++ silently invokes the copy constructor of FooBase
, because you can only keep objects of that type in your vector. Since Foo
inherits publicly from FooBase
the method FooBase::FooBase(FooBase const&)
can be called with an object of type Foo
.
So, you're not really storing Foo
s, but in fact FooBase
s. To do what you want to do you need an std::vector<FooBase*>
or std::vector<std::shared_ptr<FooBase> >
.
However, the contents of your vector, will still lack a foo
member, because the static type is still not Foo
. To get around this, you have some options. You could dynamic_cast
or static_cast
your FooBase*
into a Foo*
and then access its foo
member. But that could break, since the FooBase*
pointers might actually hold another type than Foo
.
Why don't you just use an std::vector<Foo<Bar> >
instead?
Upvotes: 2