current = new Philosopher("I think, therefore I am.");
This call to new actually gives you a
Philosopher*
. This pointer is being implicitly cast to a
Speaker*
. This works because all Philosophers are also Speakers (a Philosopher "is a" Speaker).
However that "is a" relationship is a one way street. All Philosophers are Speakers, but not all Speakers are Philosophers. A Speaker could be a Dog, for example.
This code doesn't work
current->pontificate();
because current is a Speaker, and all Speakers can't pontificate. Only Philosophers can. The program has no way to know [at compiletime] that current actually points to a Philosopher.
For instance, say you tried the following:
1 2
|
current = new Dog;
current->pontificate();
|
That obivously doesn't make sense. That's why if you have a
Speaker*
you can only do things with it that all Speakers can do. If you need to do something specific to a certain kind of speaker, you can downcast.
(Philosopher*)current
is a C-style cast which "converts" current from a Speaker* to a Philosopher*.
1 2 3 4 5 6
|
// this:
((Philosopher *)current)->pontificate();
// is basically shorthand for this:
Philosopher* p = (Philosopher *)current;
p->pontificate();
|
Note however that downcasting (and
especially C style downcasting) is dangerous, as it makes it possible to do things that cause all sorts of problems.
Take this, for example:
1 2
|
Speaker* current = new Dog;
((Philosopher *)current)->pontificate();
|
That obviously makes no sense because Dogs can't pontificate. However the code will compile without error! This leads to very strange, unpredictable, hard to find, and possibly fatal bugs in programs. And in fact, there's almost always an alternative to downcasting, so in most situations where you're doing it, you might want to rethink because there's typically a better/safer way to do what you want.
As mentioned, a safer way to downcast is to use dynamic_cast. dynamic_cast will actually confirm to make sure the Speaker
actually is a Philosopher before it actually downcasts. Ensuring that code you write will be safe. For example:
1 2 3 4 5 6 7 8 9 10 11 12 13
|
Philosopher* p = dynamic_cast<Philosopher*>(current);
if(p)
{
// 'current' really did point to a Philosopher, so we're okay
p->pontificate();
}
else
{
// 'current' did not point to a Philosopher. It must have pointed to something else (like a Dog
// or some other kind of Speaker)
// so don't use 'p' here
}
|