468,315 Members | 1,501 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 468,315 developers. It's quick & easy.

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 Tstruct 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<Appleapples_;
std::deque<Pearpears_;
std::deque<Orangeoranges_;
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,pt rdiff_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<Tbegin()
{
std::deque<T&real_cont=*reinterpret_cast<std::dequ e<T*>(containers_[IndexOf<AllFruits, T>::value]);
return iterator<T>(real_cont, real_cont.begin());
}
template<class T>
iterator<Tend()
{
std::deque<T&real_cont=*reinterpret_cast<std::dequ e<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::dequ e<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,Frui t,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<FruitFruitBox::begin()
{
return FruitBox::iterator<Fruit>(fruit_, fruit_.begin());
}

template<>
FruitBox::iterator<FruitFruitBox::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<Appleap=box.begin<Apple>();
for(; ap!=box.end<Apple>(); ++ap)
{
std::cout << "Apple iter=" << (*ap) << std::endl;
}

FruitBox::iterator<Pearpe=box.begin<Pear>();
for(; pe!=box.end<Pear>(); ++pe)
{
std::cout << "Pear iter=" << (*pe) << std::endl;
}

FruitBox::iterator<Fruitfr=box.begin<Fruit>();
for(; fr!=box.end<Fruit>(); ++fr)
{
std::cout << "Fruit iter=" << (*fr) << std::endl;
}

//box.testit(std::cout);

return 0;
}


Jun 27 '08 #1
3 1209
>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"));
uhm that's because you are putting the adresses of temporary objects
into the fruits container. There is no slicing,it's undefined
behaviour.as soon as the insert() returns Apples and such cease to
exist.
Jun 27 '08 #2
hurcan solter wrote:
>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"));
uhm that's because you are putting the adresses of temporary objects
into the fruits container. There is no slicing,it's undefined
behaviour.as soon as the insert() returns Apples and such cease to
exist.
Excellent. Thank you.

Thats so obvious now you pointed it out.

Adrian
Jun 27 '08 #3
Adrian <bi*******@bluedreamer.comwrote in news:6
_u*****************************@comcast.com:
hurcan solter wrote:
>>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"));
uhm that's because you are putting the adresses of temporary objects
into the fruits container. There is no slicing,it's undefined
behaviour.as soon as the insert() returns Apples and such cease to
exist.
Excellent. Thank you.

Thats so obvious now you pointed it out.
Note that you cannot store in the fruits container also pointers to the
actual objects stored inside various other containers as the containers
may grow and the objects array be reallocated.

When working with polymorphic objects one usually uses dynamic allocation
and containers of (smart) pointers, this avoids both the slicing problem
and object moving problem. I would suggest a container of
boost::shared_ptr<Fruit>.

hth
Paavo
Jun 27 '08 #4

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

2 posts views Thread by Michael Young | last post: by
5 posts views Thread by Peter Hagenaar | last post: by
11 posts views Thread by anongroupaccount | last post: by
3 posts views Thread by Martin Drautzburg | last post: by
15 posts views Thread by =?Utf-8?B?R2Vvcmdl?= | last post: by
3 posts views Thread by =?Utf-8?B?c29uaWNt?= | last post: by
reply views Thread by NPC403 | last post: by
reply views Thread by Teichintx | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.