I may be wrong but this is how I see it.
The main reason why we have CanvasItemVector in the first place, is we
want
to deal with all CanvasItem object transparently - Polymorphism ?.
In that particular instance, we /do/ want all of them to act generically.
We don't care about the details of each CanvasItem. I think of it like
passengers on a train. All the conductor cares about is whether you have a
ticket. (And that you behave yourself). He doesn't care if you are a
doctor, computer programmer, etc. IF you happen to get to an international
border, there will be questions regarding your national citizenship.
That's when the passenger needs to produce some kind of 'type information'.
Polymorphism, like many OO terms, does not have a single, universal
definition. Budd provides a few definition. I'll use this from his Intro
to OOP: "In programming languages, a polymorphic object is any entity, such
as a variable or function argument, that is permitted to hold values of
differing types during the course of exectution."
If we
need to know the object type, we no longer have Polymorphism.
I'm not sure that is really correct. Polymorphism seems to be a
circumstantial characteristic which is not required for all instances in
which the object exhibiting polymorphism is used.
The problem
is what happen when we introduce a new class derived from CanvasItem; the
new class will have to be handled in many different places whereever RTTI
appeared.
That may, or may not, be a problem. If the objects of the newly introduced
type are used in many different parts of the program, and require different
treatment due to their unique characteristics, that's just the nature of
programming. You can't really get away from that unless you put the
variant functionality in the object itself. There are often two options to
implementing functionality for manipulating objects. Either the
functionality is internal to objects so they /act for themselves/, or it is
implemented outside of the class, and the objects are /acted on/. In the
latter case, if you need different behavior per class, it the manipulator
needs to know what kind of object it is acting on. Sometimes it is not
reasonable (or even possible) to put functionality into the class. In such
cases, RTTI is a reasonable way to discriminate between object types.
I think it's important to keep in mind that OO principles do not require
that all objects and or functions be polymorphic. It's also important to
remember that C++ was not designed as a strictly OOPL. Furthermore, IMO,
what matters in the final analysis is not whether the program adheres
strictly to some set of definitions considered as OOP, but rather, whether
the program does what it was designed to do, is reasonably efficient,
reliable, robust, and above all maintainable.