Problems with objects getting sliced to base class
In the following code example I am trying to create a generic interface for a bunch of objects. Each concrete type is stored in its own container and the a container of pointer's to base is used so I can access all at once.
I created a specialization of the template for Fruit *'s so that it returns a reference and the code looks the same as when accessing a concrete type.
I've managed to get everything working so far except accessing all object in the container through a base iterator. When inserting into the base deque the objects get sliced back to the base class. And I have no idea why. I've tried various casts but none seem to work
Any help appreciated.
Adrian
#include <iostream>
#include <vector>
#include <string>
#include <deque>
#include <iterator>
class Fruit
{
public:
Fruit(const std::string &brand) : brand_(brand) {}
friend std::ostream &operator<<(std::ostream &os, const Fruit &rhs)
{
rhs.print(os);
return os;
}
virtual ~Fruit()=0;
protected:
std::string brand_;
private:
virtual void print(std::ostream &os) const
{
// should be pure - done for debug
os << "OOPS";
}
};
class Apple : public Fruit
{
public:
Apple(const std::string &brand) : Fruit(brand) {}
private:
void print(std::ostream &os) const
{
os << "I am " << brand_ << " apple";
}
};
class Pear : public Fruit
{
public:
Pear(const std::string &brand) : Fruit(brand) {}
void print(std::ostream &os) const
{
os << "I am " << brand_ << " pear";
}
};
class Orange : public Fruit
{
public:
Orange(const std::string &brand) : Fruit(brand) {}
void print(std::ostream &os) const
{
os << "I am " << brand_ << " orange";
}
};
template <class H, class T>
struct typelist
{
typedef H head;
typedef T tail;
};
class null_typelist {};
typedef typelist<Apple, typelist<Pear, typelist<Orange, null_typelist> > > AllFruits;
template <class TList, class T> struct IndexOf;
template<class T>
struct IndexOf<null_typelist, T>
{
enum { value=-1 };
};
template<class T, class Tail>
struct IndexOf<typelist<T, Tail>, T>
{
enum { value=0 };
};
template<class Head, class Tail, class T>
struct IndexOf<typelist<Head, Tail>, T>
{
private:
enum { temp=IndexOf<Tail, T>::value };
public:
enum { value=temp==-1?-1:1+temp };
};
Fruit::~Fruit()
{
}
class FruitBox
{
std::vector<void *> containers_;
std::deque<Apple> apples_;
std::deque<Pear> pears_;
std::deque<Orange> oranges_;
std::deque<Fruit *> fruit_;
public:
void testit(std::ostream &os)
{
for(std::deque<Fruit *>::iterator i=fruit_.begin(); i!=fruit_.end(); ++i)
{
os << *(*i) << std::endl;
}
}
FruitBox()
{
containers_.push_back(&apples_);
containers_.push_back(&pears_);
containers_.push_back(&oranges_);
}
template<class T>
class iterator : public std::iterator<std::bidirectional_iterator_tag,T,ptrdiff_t>
{
std::deque<T> *r;
typename std::deque<T>::iterator it;
public:
iterator(std::deque<T> &lst, const typename std::deque<T>::iterator &i)
:r(&lst), it(i) {}
bool operator==(const iterator &x) const {
return it==x.it;
}
bool operator!=(const iterator &x) const {
return !(*this==x);
}
typename std::deque<T>::reference operator*() const {
return *it;
}
iterator &operator++(){
++it;
return *this;
}
};
///////////////////////////////////////////////////////////////////////////////
template<class T>
iterator<T> begin()
{
std::deque<T> &real_cont=*reinterpret_cast<std::deque<T> *>(containers_[IndexOf<AllFruits, T>::value]);
return iterator<T>(real_cont, real_cont.begin());
}
template<class T>
iterator<T> end()
{
std::deque<T> &real_cont=*reinterpret_cast<std::deque<T> *>(containers_[IndexOf<AllFruits, T>::value]);
return iterator<T>(real_cont, real_cont.end());
}
///////////////////////////////////////////////////////////////////////////////
template<class T>
void insert(const T &val)
{
std::deque<T> &real_cont=*reinterpret_cast<std::deque<T> *>(containers_[IndexOf<AllFruits, T>::value]);
real_cont.push_back(val);
// fruit_.push_back(const_cast<T *>(&val));
T &ptr=const_cast<T&>(val);
fruit_.push_back(&ptr);
// std::cout << "ptr=" << ptr << std::endl;
// std::cout << "val=" << val << std::endl;
testit(std::cout);
}
private:
};
template<>
class FruitBox::iterator<Fruit> : public std::iterator<std::bidirectional_iterator_tag,Fruit,ptrdiff_t>
{
std::deque<Fruit *> *r;
std::deque<Fruit *>::iterator it;
public:
iterator(std::deque<Fruit *> &lst, const std::deque<Fruit *>::iterator &i)
:r(&lst), it(i)
{
for(std::deque<Fruit *>::const_iterator woof=lst.begin(); woof!=lst.end(); ++woof)
{
std::cout << "Woof:" << *(*woof) << std::endl;
}
if(i!=lst.end())
std::cout << "iter con=" << *(*i) << std::endl;
}
bool operator==(const iterator &x) const {
return it==x.it;
}
bool operator!=(const iterator &x) const {
return !(*this==x);
}
Fruit &operator*() const
{
std::cout << "Boo:" << *(*it) << std::endl;
return **it;
}
iterator &operator++(){
++it;
return *this;
}
};
template<>
FruitBox::iterator<Fruit> FruitBox::begin()
{
return FruitBox::iterator<Fruit>(fruit_, fruit_.begin());
}
template<>
FruitBox::iterator<Fruit> FruitBox::end()
{
return FruitBox::iterator<Fruit>(fruit_, fruit_.end());
}
int main(int argc, char *argv[])
{
FruitBox box;
box.insert(Apple("Granny Smith"));
box.insert(Apple("Golden Delicious"));
box.insert(Pear("Sweet"));
box.insert(Pear("Sour"));
box.insert(Orange("Blood"));
box.insert(Orange("Navel"));
FruitBox::iterator<Apple> ap=box.begin<Apple>();
for(; ap!=box.end<Apple>(); ++ap)
{
std::cout << "Apple iter=" << (*ap) << std::endl;
}
FruitBox::iterator<Pear> pe=box.begin<Pear>();
for(; pe!=box.end<Pear>(); ++pe)
{
std::cout << "Pear iter=" << (*pe) << std::endl;
}
FruitBox::iterator<Fruit> fr=box.begin<Fruit>();
for(; fr!=box.end<Fruit>(); ++fr)
{
std::cout << "Fruit iter=" << (*fr) << std::endl;
}
//box.testit(std::cout);
return 0;
}