It would be fun to sit down with you and see if we can't
connect the code that creates the objects to the code that
uses the objects, then remove those two dynamic_casts.
The question is more: do you want to. Should the code between
the provider and the consumer need to know about all of the
possible interfaces, as long as the provider and the consumer
are in agreement?
And in the end, isn't this the age old argument between static
type checking (a la C++) and dynamic type checking (a la
Smalltalk)? I think most of us here agree that static type
checking provides an additional, very useful measure of
security (and it's worth pointing out that all of the modern OO
languages use static type checking, even though Smalltalk
didn't). On the other hand, that security comes at a loss of
flexibility (true OO). IMHO, dynamic_cast is an almost perfect
way of recovering enough of that flexibility when it's needed,
without any more loss of security than is necessary to achieve
that flexibility---I can't just call any function on an object,
hoping that the object implements it: I must specifically ask
for a different, statically declared interface, in order to
access the additional functions. In other words, in OO in its
"truest" (or at least its original) form, you don't have
dynamic_cast, because the flexibility is built into the
language, because of the absense of static type checking. In
C++ without dynamic_cast, you loose a lot of that flexibility.
In many cases, it doesn't matter, of course, and it's often
preferable to design your code so that it won't. But many cases
isn't all, and there are cases where you need that extra measure
of flexibility.