Ok, I was reading through this entry in the FQA dealing about the issue of converting a Derived** to a Base** and why it is forbidden, and I got that the problem is that you could assign to a Base* something which is not a Derived*, so we forbid that.
So far, so good.
But, if we apply that principle in depth, why aren’t we forbidding such example?
void nasty_function(Base *b)
{
*b = Base(3); // Ouch!
}
int main(int argc, char **argv)
{
Derived *d = new Derived;
nasty_function(d); // Ooops, now *d points to a Base. What would happen now?
}
I agree that nasty_function does something idiotic, so we could say that letting that kind of conversion is fine because we enable interesting designs, but we could say that also for the double-indirection: you got a Base **, but you shouldn’t assign anything to its deference because you really don’t know where that Base ** comes, just like the Base *.
So, the question: what’s special about that extra-level-of-indirection? Maybe the point is that, with just one level of indirection, we could play with virtual operator= to avoid that, while the same machinery isn’t available on plain pointers?
No, it doesn’t. It points to a
Derived. The function simply changed theBasesubobject in the existingDerivedobject. Consider:ddoesn’t magically become aBase, does it? It’s still aDerived, but theBasepart of it changed.In pictures 🙂
This is what
BaseandDerivedobjects look like:When we have two levels of indirection it doesn’t work because the things being assigned are pointers:
Notice how neither of the
BaseorDerivedobjects in question are attempted to be changed: only the middle pointer is.But, when you only have one level of indirection, the code modifies the object itself, in a way that the object allows (it can forbid it by making private, hiding, or deleting the assignment operator from a
Base):Notice how no pointers are changed here. This is just like any other operation that changes part of an object, like
d.y = 42;.