Inheritance and iterators

Started by
10 comments, last by MrPickle 13 years, 11 months ago
I have 2 classes like so:
class Shape
{
public:
   int width, height;
   virtual int area() { return 0; }
};

class Square : public Shape
{
public:
   int area() { return width*height; }
};

Then I have a vector defined like so: std::vector<Shape*> shapes; I try and iterate through the vector like this:
for(std::vector<Shape*>::iterator it = shapes.begin(); it != shapes.end(); it++)
{
   Shape &s = **it;
   
   s.area();
}
The problem is that whenever I call area, even if s is a Square, it calls Shape's area function. I thought that the virtual keyword was so that the inheriting class can redefine the function? Could somebody please tell me why Shape's area function is called instead of Square's area function?
Here to learn :)
Advertisement
It is calling Shape::area because o object slicing. Try using pointers instead:

for(std::vector<Shape*>::iterator it = shapes.begin(); it != shapes.end(); it++){   Shape *s = *it;      s->area();}
.
Are you sure that's the code you're using? This sample using those classes verbatim works fine and calls Square::area:
int main(){	std::vector<Shape*> v;	Shape* s = new Square;	v.push_back(s);	Shape& s2 = **v.begin();	s2.area();}

It's possible that you don't really have a Square, even though you think you do...

EDIT: I should add that if you breakpoint in the debugger and watch s, the debugger should tell you what the actual type is when you expand the class.
Beat to the punch, well kinda, I was half-right, but what the above poster stated there is no square is basically what I was getting at. Good luck to you.
Oops, in my attempt to make an example without all of the excess I missed out what I figure's causing the problem.

I'm trying to overload Square::area() with one function taking one derived class from shape and the second taking another derived class from shape and I have defined the class Shape as taking a Shape. (if this makes sense)

do I have declare a virtual function for each overload?
Here to learn :)
Functions are only called virtually when you use a pointer, so the line below can only call Shape members.

Shape &s = **it;

Should be

Shape* s = *it;

You should post your code
Quote:Original post by MrPickle
do I have declare a virtual function for each overload?
Each overload is a distinct and different function, and each of them needs to exist as a virtual in the base class, yes.
Quote:Original post by taz0010
Functions are only called virtually when you use a pointer, so the line below can only call Shape members.
No! This is completely false. Calling a virtual function from a reference or a pointer will do the same thing.

xissburg posted the same false information earlier.

The only time slicing will occur is if you copy the object by value
Shape s = **it;//make a copy into a new shape objects.area();//object has been sliced, this will always call Shape::area
Quote:No! This is completely false. Calling a virtual function from a reference or a pointer will do the same thing.


Interesting. Didn't realise this.

Quote:The only time slicing will occur is if you copy the object by value


I'm also getting slicing when I copy using references. (Which is in effect a copy by value of course)

B* der = new D(1,2,3);B* der2 = new D(4,5,6);B& ref = *der;B& ref2 = *der2;ref = ref2;


This seems a little confusing. I think I'll stick to using pointers when inheritance is concerned.
Quote:Original post by taz0010
B* der = new D(1,2,3);B* der2 = new D(4,5,6);B& ref = *der;B& ref2 = *der2;ref = ref2;
Yeah, the references are like a "short-hand" for writing whatever they're bound do, so your example of "ref = ref2;" is the same as writing:
*der = *der2;
Which copies the value, not the addresses.
Quote:Original post by taz0010
Quote:No! This is completely false. Calling a virtual function from a reference or a pointer will do the same thing.


Interesting. Didn't realise this.

Quote:The only time slicing will occur is if you copy the object by value


I'm also getting slicing when I copy using references. (Which is in effect a copy by value of course)

B* der = new D(1,2,3);B* der2 = new D(4,5,6);B& ref = *der;B& ref2 = *der2;ref = ref2;


This seems a little confusing. I think I'll stick to using pointers when inheritance is concerned.


You would get the same slicing with: *der = *der2; which, strictly speaking, doesn't use any references. You may want to look into boost::noncopyable, or making your copy constructor and assignment operator private, to prevent this kind of blatant error, in the case of inheritance trees. It will work, no matter which you're using.

This topic is closed to new replies.

Advertisement