# Inheritance and iterators

This topic is 2856 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

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?

##### Share on other sites
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();}

##### Share on other sites
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.

##### Share on other sites
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.

##### Share on other sites
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?

##### Share on other sites
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;

##### Share on other sites
Quote:
 Original post by MrPickledo 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 taz0010Functions 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

##### Share on other sites
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.

##### Share on other sites
Quote:
 Original post by taz0010B* 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.

##### Share on other sites
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.

##### Share on other sites
Quote:
 Original post by taz0010I'm also getting slicing when I copy using references. (Which is in effect a copy by value of course)

The phrase "copy by value" doesn't really mean anything; copying is copying.

The point of a reference is to, well, refer to the referred-to thing. If you say to assign to the thing you're referring to, then that assignment takes place. A pointer points at the pointed-at thing; in effect, it's a separate entity whereas the reference is just another name for the value. So the difference in copying behaviour is exactly what should be expected and should not be confusing at all. It also happens to be very convenient in a lot of cases: it lets you write functionality with stronger guarantees (because a C++ reference can't legally be "null" or invalid), and avoids writing so much of what I call "*&*&ing syntax". :)

Quote:
 I think I'll stick to using pointers when inheritance is concerned.

Ultimately, you will normally need to heap-allocate to make useful use of inheritance (but note that there are other ways to do polymorphism :) ), so you'll have pointers anyway. But you can at least wrap them up in smart pointer classes to avoid manual memory management. And writing something like 'X& x = **it;' is idiomatic, and lets you access members with . instead of ->.