You have a couple of alternatives:
(a) Adding you own type field to the base class
class Animal
{
public:
int m_type;
...
}
That is not very object oriented and would be my last resort.
(b) Use the run-time type information system of C++:
Cat* pCat = dynamic_cast<Cat*> (arr[i]);
if (pCat != NULL)
pCat->age = 14;
Don't forget that run-time type information is only available for polymorphic classes, i.e. classes that have at least one virtual function. That is no problem in your case. In fact, you should make the destructor of your base class virtual, so you can delete your array elements properly!
This alternative is a little better than (a) in terms of object orientation, but still kind of a last resort for some existing code that was not properly designed.
(c) Create a virtual function that does whatever you want to do. For example, say you want to adjust all animal ages by some formula that is animal type specific. You could implement a virtual function like:
class Animal
{
public:
virtual void AdjustAge () = 0;
...
}
class Cat
{
public:
virtual void AdjustAge ()
{
age = age * CAT_SPECIFIC_FACTOR;
}
...
}
class Dog
{
public:
virtual void AdjustAge ()
{
age = age * DOG_SPECIFIC_FACTOR + 5;
}
...
}
Then in the calling code you would just do:
for (i = 0; i < ....)
arr[i]->AdjustAge();
This would be the most object oriented solution. Making AdjustAge an abstract virtual function (the = 0;) makes sure that you don't forget to implement the function in each derived class. This maintenance friendly and easy to figure out for someone who has to maintain your code later on.