I mentioned initializers yesterday, here’s what I’m talking about:
std::vector<Shape> shapes = {
Cube(glm::vec3(1.5, 0, 0)),
Cube(glm::vec3(-1.5, 0, 0))
};
This stores objects instead of references, and then the for loop looks like this:
for (auto &shape : shapes)
{
// do stuff with shape
}
You can take out the &
, too, and I’m going to be brutally honest with y’all I don’t know what the difference is.
Don’t matter though, because guess what – this doesn’t work! All of the Cube
s act like Shape
s, even though I’ve dutifully marked the functions as virtual. Why is this? Turns out there is something called “Object slicing”. When I assign a Cube
to a Shape
, The piece of Cube
that makes it different from Shape
gets sawed off, and there’s just a Shape
left that doesn’t know it was ever a Cube
. Why would anyone ever want to do this? You’d think at least there’d be some kind of ‘slice’ keyword so that you have to tell the compiler, yes, I really want to do this nonsensical thing. It would keep a lot of people out of trouble, not least of all myself.
This begs for an experiment, though, that may unravel some of the mysteries of &
! Here’s my theory. Since object slicing is a thing, then if I have an array of Cube
s and I do this:
for (Shape shape : cubes)
{
// do stuff with shape
}
The cubes
will get sliced, and act like Shape
s. But if I do this:
for (Shape &shape : cubes)
{
// do stuff with shape
}
The cubes
should not get sliced, and act like Cube
s! Because it’s a reference, I’m not actually copying the object! Right?? Do I know my &
??
It turns out I do, but there’s an even more bizarre side effect that is, in retrospect, obvious… if you do anything in this for loop (the first one, without the &) that affects the state of the object, it only affects the copy, not the original one in the array! So in that situation the &
really is your friend, in many ways.
This is all fascinating, but I’m going back to pointers so that I can have my polymorphism.