I'm assuming pAnimal is of type Animal* and pDog is of type Dog*.
When you assign the new Dog() to pAnimal, it casts the Dog* to an Animal* which is perfectly legal, since Dog derives from Animal.
Going back the other way (i.e. casting from Animal* to Dog*) is different however. Since there are situations where this would be an invalid cast (i.e. if pAnimal pointed to a Cat), the compiler requires that you explicitly cast it, for example:
pDog = static_cast<Dog*>(pAnimal);
You will want to use dynamic_cast if you aren't sure of the type, for example:
pDog = dynamic_cast<Dog*>(pAnimal);
if (!pDog)
{
// invalid cast, pAnimal didn't point to a Dog
}
dynamic_cast will check if the cast is valid, and if not it will return a null pointer.
Edit: using static_cast may give a slight performance gain over dynamic_cast, however should only be used if you are 110% sure of the type.