IAnimal anAnimal = new Cat();
You're right. This is doesn't really have a use case, since it has no direct advantage. Since you're hardcoding the object's type (
Cat), there is nothing gained from downcasting the type of the variable that references the object.
However, your argument does not hold true when
Cat is not hardcoded:
IAnimal anAnimal = myAnimalFinder.FindByName("Fido");
You don't know what animal you're going to get back.
Assuming your software is sold to vets, the result (based on the same name) may differ from vet to vet. Vet A has treated a dog named Fido, vet B has treated a cat named Fido.
This is the real use case, one that actually makes sense in context. The simplified version you were initially referring to is most commonly found in examples, not live code.
But it won't let you do anAnimal.meow() even though it's a Cat
Looking at the real use case, it becomes clear why you can't call
meow(). You have no way to guarantee that you're actually going to get a
Cat back, so there's no way to know if the returned animal can meow or not.