c++ problem with polymorphism and vectors of pointers - c++

Consider the following example code:
class Foo
{
};
class Bar : public Foo
{
};
class FooCollection
{
protected:
vector<shared_ptr<Foo> > d_foos;
};
class BarCollection : public FooCollection
{
public:
vector<shared_ptr<Bar> > &getBars()
{
// return d_foos won't do here...
}
};
I have a problem like this in my current project. The client code uses BarCollection, which stores pointers to Bars in d_foos which is declared in FooCollection. I'd now like to expose the collection of pointers to Bars to the client code. I could just give the client code access to the vector of pointers to Foos and cast these to pointers to Bars in the client code, but this feels wrong since the client doesn't have to know about Foo's existence.
I could also define a get() member that retrieves objects from d_foos and casts them, but this feels quite clumsy. Preferably, I'd like to just return d_foos as a vector<shared_ptr<Bar> > &, but I cannot seem to do this.
It could also be that my design is just plain wrong. It seemed to most natural solution though, as Bar is a specialization of Foo and BarCollection is a specialization of FooCollection and they share functionality.
Could you suggest nice solutions to implement getBars in BarCollection or better design alternatives?
Edit:
Turns out my design was bad indeed. BarCollection is not a FooCollection, despite of requiring all of FooCollection's functionality. My current solution based on the answers below -- which is a lot cleaner -- is now:
class Foo
{
};
class Bar : public Foo
{
};
template<class T>
class Collection
{
vector<shared_ptr<T> > d_items;
};
typedef Collection<Foo> FooCollection;
class BarCollection : public Collection<Bar>
{
// Additional stuff here.
};
Thanks for all the excellent suggestions and examples!

I would suggest exposing iterators from your container classes, instead of the member container. That way it won't matter what the container type is.

The problem is you are trying to mix-and-match two different, pretty-much independent kinds of polymorphism in a way that won't work. The compile-time, type-safe polymorphism of templates won't allow you to substitute a base type for a derived type. C++'s template system makes no association between
class<Foo>
and
class<Bar>
One suggestion might be to create a Foo derived adapter that would cast down to the correct class:
template <class derived, class base>
class DowncastContainerAdapter
{
private:
std::vector< boost::shared_ptr<base> >::iterator curr;
std::vector< boost::shared_ptr<base> >::const_iterator end;
public:
DowncastContainerAdapter(/*setup curr & end iterators*/)
{
// assert derived actually is derived from base
}
boost::shared_ptr<derived> GetNext()
{
// increment iterator
++curr;
return dynamic_cast<base>(*curr);
}
bool IsEnd()
{
return (curr == end);
}
};
Note this class will have the same problem as an iterator, operation on the vector may invalidate this class.
Another thought
You may not realize it, but it may be perfectly fine to just return a vector of Foo. The user of Bar already must have full knowledge of Foo, since by including Bar.h they must get Foo.h through Bar.h. The reason being that for Bar to inherit from Foo, it must have full knowledge of the class via Foo.h. I would suggest rather than using the solution above, if it's possible make Foo (or a super class of Foo) an interface class and pass around vectors of pointers to that interface class. This is a pretty commonly seen pattern and won't raise the eyebrows that this wonky solution I came up with might :). Then again you may have your reasons. Good luck either way.

template<class T>
class MyContainer {
vector<shared_ptr<T> > d_foos;
public:
vector<shared_ptr<T> > & getVector();
};
class FooCollection : public MyContainer<Foo> {
};
class BarCollection : public MyContainer<Bar> {
};

The question is, why would you do that? If you give the user a collection of pointers to Bar, you assume, that there are only Bars in it, so internally storing the pointers in a collection to Foo makes no sense. If you store different subtypes of Foo in your collection of pointer to Foo, you cannot return it as a collection of pointers to Bar, since not all objects in there are Bars.
In the first case, (you know that you have only bars) you should use a templated approach as suggested above.
Otherwise, you have to rethink, what you really want.

Can you not replace this with a Collection templatized on either Foo / Bar?, something like this
class Collection<T> {
protected:
vector<shared_ptr<T> > d_foos;
};
typedef Collection<Foo> FooCollection;
typedef Collection<Bar> BarCollection;

Do you have a special need to have BarCollection derived from FooCollection? Because generally a BarCollection is not a FooCollection, usually a lot of the things that can be done with a FooCollection should not be done with a BarCollection. For example:
BarCollection *bc = new BarCollection();
FooCollection *fc = bc; // They are derived from each other to be able to do this
fc->addFoo(Foo()); // Of course we can add a Foo to a FooCollection
Now we have added a Foo object to what is supposed to be a BarCollection. If the BarCollection tries to access this newly added element and expects it to be a Bar, all kinds of ugly things will happen.
So usually you want to avoid this and don't have your collection classes derived from each other. See also questions about casting containers of derived types for more answers on this topic...

First of all, let's talk about shared_ptr. Do you know about: boost::detail::dynamic_cast_tag ?
shared_ptr<Foo> fooPtr(new Bar());
shared_ptr<Bar> barPtr(fooPtr, boost::detail::dynamic_cast_tag());
This is a very handy way. Under the cover it just performs a dynamic_cast, nothing fancy there but an easier notation. The contract is the same that the classic one: if the object pointed to does not actually is a Bar (or derived from it), then you get a null pointer.
Back to your question: BAD CODE.
BarCollection is NOT a FooCollection, as mentioned you are therefore in trouble because you could introduce other elements in the vector of pointers that Bar ones.
I won't extend on that though, because this is beyond the question at hand, and I think that we (as those trying to answer) should restrain ourselves from that.
You cannot pass a reference, but you can pass a View.
Basically, a View is a new object that act as a Proxy to the old one. It's relatively easy using Boost.Iterators from example.
class VectorView
{
typedef std::vector< std::shared_ptr<Foo> > base_type;
public:
typedef Bar value_type;
// all the cluttering
class iterator: boost::iterator::iterator_adaptor<
iterator,
typename base_type::iterator,
std::shared_ptr<Bar>
>
{
typename iterator_adaptor::reference dereference() const
{
// If you have a heart weakness, you'd better stop here...
return reinterpret_cast< std::shared_ptr<Bar> >(this->base_reference());
}
};
// idem for const_iterator
// On to the method forwarding
iterator begin() { return iterator(m_reference.begin()); }
private:
base_type& m_reference;
}; // class VectorView
The real problem here is of course the reference bit. Getting a NEW shared_ptr object is easy, and allow to perform a dynamic_cast as required. Getting a reference to the ORIGINAL shared_ptr but interpreted as the required type... is really not what I like to see in code.
Note:
There might be a way to do better than that using Boost.Fusion transform_view class, but I could not figure it out.
In particular, using transform_view I can get shared_ptr<Bar> but I can't get a shared_ptr<Bar>& when I dereference my iterator, which is annoying given that the only use of returning a reference to the underlying vector (and not a const_reference) is to actually modify the structure of the vector and the objects it contains.
Note 2:
Please consider refactoring. There have been excellent suggestions there.

Related

How to pass a container of derived type to a function needing a container of base type [duplicate]

Consider these classes.
class Base
{
...
};
class Derived : public Base
{
...
};
this function
void BaseFoo( std::vector<Base*>vec )
{
...
}
And finally my vector
std::vector<Derived*>derived;
I want to pass derived to function BaseFoo, but the compiler doesn't let me. How do I solve this, without copying the whole vector to a std::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.
Instead of passing the container object (vector<>), pass in begin and end iterators like the rest of the STL algorithms. The function that receives them will be templated, and it won't matter if you pass in Derived* or Base*.
This problem occurs in programming languages that have mutable containers. You cannot pass around a mutable bag of apples as a bag of fruit because you cannot be sure that someone else does not put a lemon into that bag of fruit, after which it no longer qualifies as a bag of apples. If the bag of apples were not mutable, passing it around as a bag of fruit would be fine. Search for covariance/contravariance.
one option is to use a template
template<typename T>
void BaseFoo( const std::vector<T*>& vec)
{
...
}
The drawback is that the implementation has to be in the header and you will get a little code bloat. You will wind up with different functions being instantiated for each type, but the code stays the same. Depending on the use case it's a quick and dirty solution.
Edit, I should note the reason we need a template here is because we are trying to write the same code for unrelated types as noted by several other posters. Templates allow you do solve these exact problems. I also updated it to use a const reference. You should also pass "heavy" objects like a vector by const reference when you don't need a copy, which is basically always.
Generally you would start with a container of base pointers, not the other way.
If you dealing with a third-party library, and this is your only hope, then you can do this:
BaseFoo (*reinterpret_cast<std::vector<Base *> *>(&derived));
Otherwise fix your code with one of the other suggesstions.
Taking Matt Price's answer from above, given that you know in advance what types you want to use with your function, you can declare the function template in the header file, and then add explicit instantiations for those types:
// BaseFoo.h
template<typename T>
void BaseFoo( const std::vector<T*>& vec);
// BaseFoo.cpp
template<typename T>
void BaseFoo( const std::vector<T*>& vec);
{
...
}
// Explicit instantiation means no need for definition in the header file.
template void BaseFoo<Base> ( const std::vector<Base*>& vec );
template void BaseFoo<Derived> ( const std::vector<Derived*>& vec );
If std::vector supported what you're asking for, then it would be possible to defeat the C++ type system without using any casts (edit: ChrisN's link to the C++ FAQ Lite talks about the same issue):
class Base {};
class Derived1 : public Base {};
class Derived2 : public Base {};
void pushStuff(std::vector<Base*>& vec) {
vec.push_back(new Derived2);
vec.push_back(new Base);
}
...
std::vector<Derived1*> vec;
pushStuff(vec); // Not legal
// Now vec contains a Derived2 and a Base!
Since your BaseFoo() function takes the vector by value, it cannot modify the original vector that you passed in, so what I wrote would not be possible. But if it takes a non-const reference and you use reinterpret_cast<std::vector<Base*>&>() to pass your std::vector<Derived*>, you might not get the result that you want, and your program might crash.
Java arrays support covariant subtyping, and this requires Java to do a runtime type check every time you store a value in an array. This too is undesirable.
They are unrelated types -- you can't.

Storing templated objects in a vector (Storing Class<int>, Class<double> in a single vector)

There is a templated class, let it be
template<typename T> class A { std::vector<T> data; };
The problem I am facing here is, users can create several types of this class, but I need to track them, best case is I have a reference of these objects in another vector, but that would not work since all types are different.
Can you recommend a good design pattern which can encapsulate this.
I can store pointers and then typecast it, but its not elegant.
I can change the architecture as well, if the solution provided is good enough.
The basic question I am trying to solve is, I have a class of vector of custom types, how do I store them.
As previous comments stated - you first need to make sure this is what you need.
With that been said, I had a similar requirement in a project of mine, which I eventually solved with inheritance and PIMPL, as follows:
class A{
private:
struct Abstract {
virtual void f() = 0;
};
template <typename T>
struct Implementation : public Abstract {
std::vector<T> data;
virtual void f() {...}
};
std::unique_ptr<Abstract> impl;
public:
template <typename T>
A(): impl(std::make_unique<Implementation<T> >()){}
void f() {impl->f();}
};
This allows you to create a container of objects of type A, and access them via the public interface defined therein (the method f). The underlying type T of each A object is specified on construction. All other implementation details specific to the type T are hidden.
The solution suffers the inherent overhead of virtual functions. I'm not sure how it compares to the std::any approach performance-wise.
std::any is the modern c++17 solution. Specifically, you should use
A<int> a;
a.data.push_back(0);
// fill refernces...
std::vector<std::any> refernces;
refernces.push_back(&a.data[0]);
// check which type is active.
if(int** iPtr = std::any_cast<int*>(&references[0]); iPtr != nullptr)
{
// its an int*
int& i = **iPtr;
// do something with i.
}
These pointers can point into the A<int>::data and A<double>::data vectors.
For a complete reference, see here https://en.cppreference.com/w/cpp/utility/any.

Use of the "memberspace" idiom?

Today I learned about the C++ "memberspace" idiom, which roughly abuses a property of C++ that makes T::bar as well as T.bar work, when T is both a type and an object in some scope.
struct A {
struct Controls {
/* put some typedefs/data/functions here */
} Controls;
};
// Can be used as a type and value
A a;
A::Controls::iterator it = a.Controls.begin();
Have you ever used this idiom in practice? Have you found it useful? What's some good or the best application of the idiom?
No, I have never used that technique (and I don't think it deserves to be called an "idiom"):
Since I haven't used it, I haven't found it useful.
A good application of that technique could be to confuse other programmers.
Another application could be to write a techno-babble article about how wonderful it is for some imagined never-in-practice encountered problem, perhaps obfuscated with lots of template metaprogramming?
Dunno, best application would probably be to write an article about all those silly-rules, like you can also have a struct and a function of the same name in the same scope, as I recall, and point out how anything that those can accomplish, can be accomplished much better by staying away from the darker corners of the language. :-) Articles don't pay much in moneys but they pay in respect and are fun to write. Please write it (TIA).
Cheers & hth.,
As #Steve already said in a comment, the fact that the nested type and the instance of this type have the same name is not a central aspect of this technique. To increase encapsulation, we could even use a member function to access the instance (even though it would less look like a namespace qualification). For example, the example you gave could be rewritten as follow without any drawback (well, maybe there are, but I can't find any at the moment):
struct A
{
struct Controls
{
//typedefs/data/functions
};
const Controls & getControls() { return controls_; }
private:
Controls controls_;
};
A a;
A::Controls::iterator = a.getControls().begin();
Here is how I see memberspaces. The goal of memberspaces is to divide the naming space of a class in order to group together related typedefs and methods. The Controls class above could be defined outside of A, but it is so tightly connected to A (each A is associated with a Controls, and vice-versa, a Controls is nothing more than a view on the object A in which it is contained) that it feels "natural" to make it a member of A, and possibly also make it friend with A (if there is a need to access A's internals).
So basically memberspaces let us define one or several views on a single object, without polluting the enclosing class namespace. As noted in the article, this can be quite interesting when you want to provide several ways to iterate over an object of your class.
For example, let's assume that I am writing a class for representing C++ classes; let's call it Class. A Class has a name, and the list of all its base classes. For convenience reasons, I would like a Class to also store the list of all the classes that inherit from it (its derived classes). So I would have a code like that:
class Class
{
string name_;
list< shared_ptr< Class > > baseClasses_;
list< shared_ptr< Class > > derivedClasses_;
};
Now, I need some member functions to add/remove base classes/derived classes:
class Class
{
public:
void addBaseClass( shared_ptr< Class > base );
void removeBaseClass( shared_ptr< Class > base );
void addDerivedClass( shared_ptr< Class > derived );
void removeDerivedClass( shared_ptr< Class > derived );
private:
//... same as before
};
And sometimes, I might need to add a way to iterate over base classes and derived classes:
class Class
{
public:
typedef list< shared_ptr< Class > >::const_iterator const_iterator;
const_iterator baseClassesBegin() const;
const_iterator baseClassesEnd() const;
const_iterator derivedClassesBegin() const;
const_iterator derivedClassesEnd() const;
//...same as before
};
The amount of names we are dealing with is still manageable, but what if we want to add reverse iteration? What if we change the underlying type for storing derived classes? That would add another bunch of typedefs. Moreover, you have probably noticed that the way we provide access to begin and end iterators does not follow the standard naming, which means we can't use generic algorithms relying on it (such as Boost.Range) without additional effort.
In fact, it is obvious when looking at the member functions name that we used a prefix/suffix to logically group them, things that we try to avoid now that we have namespaces. But since we can't have namespaces in classes, we need to use a trick.
Now, using memberspaces, we encapsulate all base-related and derived-related information in their own class, which not only let us group together related data/operations, but can also reduce code duplication: since the code for manipulating base classes and derived classes is the same, we can even use a single nested class:
class Class
{
struct ClassesContainer
{
typedef list< shared_ptr< Class > > const_iterator;
ClassesContainer( list< shared_ptr< Class > > & classes )
: classes_( classes )
{}
const_iterator begin() const { return classes_.begin(); }
const_iterator end() const { return classes_.end(); }
void add( shared_ptr< Class > someClass ) { classes_.push_back( someClass ); }
void remove( shared_ptr< Class > someClass ) { classes.erase( someClass ); }
private:
list< shared_ptr< Class > > & classes_;
};
public:
typedef ClassesContainer BaseClasses;
typedef ClassesContainer DerivedClasses;
// public member for simplicity; could be accessible through a function
BaseClasses baseClasses; // constructed with baseClasses_
DerivedClasses derivedClasses; // constructed with derivedClasses_
// ... same as before
};
Now I can do:
Class c;
Class::DerivedClasses::const_iterator = c.derivedClasses.begin();
boost::algorithm::find( c.derivedClasses, & c );
...
In this example, the nested class is not so coupled to Class, so it could be defined outside, but you could find examples with a stronger bound.
Well, after this long post, I notice that I did not really answer your question :). So no, I never actually used memberspaces in my code, but I think it has its applications.
I have considered it once or twice, notably when I was writing a facade class for a library: the facade was meant to make the library easier to use by having a single entry point, but as a consequence it had several member functions, which were all related, but with different degrees of "relatedness". Moreover, it represented a collection of objects, so it contained iteration-related typedefs and member functions in addition to "features-oriented" member functions. I considered using memberspaces to divide the class in logical "subspaces" in order to have a cleaner interface. Don't know why I haven't done it.
No, I've never used that.
A good use for it? Maybe you can use it to show your colleagues that you are better they are... just like some pleople use templates where they shoudn't, for a complex solution to a simple problem (note that templates, unlike memberspace idiom, sometimes are useful).
Any syntax flexibility is always welcomed regardless of whether is it is potentially confusing or not. In fact the trick is used in boost.array, this is a minimal implementation:
#include<cassert>
template<unsigned N>
struct fixed_array{ /* bla bla */
static unsigned size(){
return N;
}
};
int main(){
fixed_array<3> arr;
assert(arr.size() == 3); //like a stl container
assert(fixed_array<3>::size() == 3); //more proper, but less generic wrt stl containers
return 0;
}
so if the user wants to see a static member function/static member variable/nested class as a property of the instance and not the class then he/she can. Useful to write generic code for example, and it is not confusing at all in this example.

C++ Templates: Coding error or compiler bug?

I'm trying to use templates to get std:list of items, where each item has a pointer to the list which contains it, but I keep hitting a compiler message.
Here's a very stripped down version of the code.
template <class E> class Item
{
public:
E* owner; // pointer to list that owns us.
};
template <class E> class BaseList: public std::list<E>
{
protected:
typedef std::list<E> inherited;
public:
void push_back(const E &e)
{
E tmp(e);
tmp.owner = this; // This line gives the error.
inherited::push_back(tmp);
}
};
class MyList;
class MyItem : public Item<MyList>
{
};
class MyList : public BaseList<MyItem>
{
};
void foo() // test code to instantiate template
{
MyList l;
MyItem m;
l.push_back(m);
}
However, my compiler barfs at the line:-
tmp.owner = this;
Error is:
[BCC32 Error] Unit7.cpp(30): E2034 Cannot convert 'BaseList<MyItem> * const' to 'MyList *'
It's like "this" has somehow become const, but I can't see why. Compiler is Codegear C++Builder 2009.
I admit I'm not 100% happy using templates, so I'm unsure if this is my problem or the compilers. The same code without template use compiles fine, but obviously that's not what I want, as I have several item/list classes that want to work this way.
Also, is there a better technique that would avoid having all the "owner" pointers in each item?
EDIT: I think I stripped the example down too far: "MyList" actually introduces new methods, which "MyItem" must then access through the "owner" pointer.
SUMMARY: Thanks for all comments and answers. As the accepted answer says, the problem is simply one of type incompatibility between pointer to a BaseList vs. MyList.
The issues raised about deriving from STL containers and alternative designs are also helpful, but the solution I've used is essentially identical to Luc Touraille's one below.
At line 30, "this" is a pointer to a BaseList<MyIteM>, not a MyList. You can substitute a class with a derived one, but not the other way around.
You can either typedef MyList to be a BaseList<MyItem>, like so:
typedef BaseList<MyItem> MyList
or let MyItem derive from Item<BaseList<MyItem> > instead.
When you derive from a type, you create a different type. When you typedef, you create an alias for that type. So when you typedef the compiler will accept this.
In addition to the answers you already have, I would also point out that the standard library collection classes are not intended to be derived from, as they do not have virtual destructors, and none of their member functions is virtual.
Shouldn't it be tmp.owner = static_cast<MyList*>(this). The type of E is MyList in the MyItem hence E* will be MyList* . The type of this pointer will be BaseList*, hence compiler gives the error that you can not convert the base class pointer to the derived class pointer.
It's hard to say if there's a better solution, when you don't say what it is you need.
Why do each element need a pointer to the list they're stored in?
Anyway, bad things can happen when you inherit from standard containers. They don't have virtual destructors, so you have to be very careful.
A better solution might be to just provide a free function performing the push_back:
template <typename T>
void push_back(std::list<T>& list, const T& t) {
T tmp(t);
tmp.owner = this;
list.push_back(tmp);
}
Apart from avoiding the nonvirtual destructor problem, it also solves your compiler error, because you now only have one type of list.
Of course, if we know why you need this owner pointer in the first place, better still solutions may exist.
Edit
In response to your edit and the comments, use composition, not inheritance:
struct House {
std::string zipcode;
std::list<Person> persons;
void AddPerson(const Person& person) {
Person tmp(person);
tmp.owner = this; // The owner field should be a house, not the list of persons.
persons.push_back(tmp);
}
};
Although I'm not sold on the almost circular references you get when a House stores a list of Persons, and a Person has a pointer to the House it's in.
I'd prefer to decouple these classes as much as possible. If I want to send a letter to a person, I'd call SendLetter(Person, House). Send a letter to this person in that house.
On the side note, you should not extend any classes from std, they are not built for it.
Specifically they don't have virtual destructor so when you call delete on pointer to base class your derived class's destructor will never get called.
You can read more on it Advice on a better way to extend C++ STL container with user-defined methods
I like jalf's free function idea. I'd make it:
template <class X, class Y> // X must have a push_back(Y) member, Y must have an X* owner member
void push_back(X& container, Y value)
{
value.owner = container;
container.push_back(value);
}
This is agnostic over whether the X passed is
a container itself,
is derived from a container as in the original code
or contains a container and has a forwarding push_back function
As it has already been pointed out, the affectation
tmp.owner = this;
fails because this doesn't have the same type as tmp.owner. One solution is to perform a cast, but to do so, you need to provide the container type to BaseList. This can be done using a typedef in Item. Here is the code:
template <class Item> class BaseList
{
public:
void push_back(Item i)
{
i.owner = static_cast<Item::containerType *>(this); // note the cast
items.push_back(i);
}
Item & back() { return items.back(); }
protected:
std::list<Item> items;
};
template <class Container> class Item
{
public:
typedef Container containerType; // Typedef used by BaseList
containerType* owner; // pointer to list that owns us.
};
I also removed the public derivation of std::list: as many said, this is (most of the time) best avoided ; you should consider using composition, or maybe private inheritance.
P.S.: I tried making owner private and BaseList<Item>::push_back friend of Item, but I didn't manage to do it. Is it possible at all? (If too long to answer in comment, feel free to ask a question and answer it)
Regarding const: The type BaseList<MyItem> * const that the compiler mentions is a red herring -- it's not a pointer-to-a-const-object, but a pointer that is const, i.e. an address that won't change. (When you think about it, this never changes to point to something else, does it?)

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

Consider these classes.
class Base
{
...
};
class Derived : public Base
{
...
};
this function
void BaseFoo( std::vector<Base*>vec )
{
...
}
And finally my vector
std::vector<Derived*>derived;
I want to pass derived to function BaseFoo, but the compiler doesn't let me. How do I solve this, without copying the whole vector to a std::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.
Instead of passing the container object (vector<>), pass in begin and end iterators like the rest of the STL algorithms. The function that receives them will be templated, and it won't matter if you pass in Derived* or Base*.
This problem occurs in programming languages that have mutable containers. You cannot pass around a mutable bag of apples as a bag of fruit because you cannot be sure that someone else does not put a lemon into that bag of fruit, after which it no longer qualifies as a bag of apples. If the bag of apples were not mutable, passing it around as a bag of fruit would be fine. Search for covariance/contravariance.
one option is to use a template
template<typename T>
void BaseFoo( const std::vector<T*>& vec)
{
...
}
The drawback is that the implementation has to be in the header and you will get a little code bloat. You will wind up with different functions being instantiated for each type, but the code stays the same. Depending on the use case it's a quick and dirty solution.
Edit, I should note the reason we need a template here is because we are trying to write the same code for unrelated types as noted by several other posters. Templates allow you do solve these exact problems. I also updated it to use a const reference. You should also pass "heavy" objects like a vector by const reference when you don't need a copy, which is basically always.
Generally you would start with a container of base pointers, not the other way.
If you dealing with a third-party library, and this is your only hope, then you can do this:
BaseFoo (*reinterpret_cast<std::vector<Base *> *>(&derived));
Otherwise fix your code with one of the other suggesstions.
Taking Matt Price's answer from above, given that you know in advance what types you want to use with your function, you can declare the function template in the header file, and then add explicit instantiations for those types:
// BaseFoo.h
template<typename T>
void BaseFoo( const std::vector<T*>& vec);
// BaseFoo.cpp
template<typename T>
void BaseFoo( const std::vector<T*>& vec);
{
...
}
// Explicit instantiation means no need for definition in the header file.
template void BaseFoo<Base> ( const std::vector<Base*>& vec );
template void BaseFoo<Derived> ( const std::vector<Derived*>& vec );
If std::vector supported what you're asking for, then it would be possible to defeat the C++ type system without using any casts (edit: ChrisN's link to the C++ FAQ Lite talks about the same issue):
class Base {};
class Derived1 : public Base {};
class Derived2 : public Base {};
void pushStuff(std::vector<Base*>& vec) {
vec.push_back(new Derived2);
vec.push_back(new Base);
}
...
std::vector<Derived1*> vec;
pushStuff(vec); // Not legal
// Now vec contains a Derived2 and a Base!
Since your BaseFoo() function takes the vector by value, it cannot modify the original vector that you passed in, so what I wrote would not be possible. But if it takes a non-const reference and you use reinterpret_cast<std::vector<Base*>&>() to pass your std::vector<Derived*>, you might not get the result that you want, and your program might crash.
Java arrays support covariant subtyping, and this requires Java to do a runtime type check every time you store a value in an array. This too is undesirable.
They are unrelated types -- you can't.