Массивы и наследование с++

Изучаю с++, столкнулся с проблемой. Есть класс Animals. От него два производных класса Cat и Dog. Как сделать массив из объектов Cat и Dog, чтобы можно было обращаться к ним по индексу массива? При обращении к полю класса вываливается ошибка, что в классе Animals нет поля age (пример в функции main). Его там действительно нет, но и я ведь обращаюсь к производному классу, где это поле присутствует... Заранее спасибо за помощь!

class Animals{
public:
    Animals(){}
};
class Cat: public Animals {
public:
    int age;
    std::string name;

    Cat() {
        this->age = 0;
        this->name = "";
    }
};

class Dog: public Animals{
public:
    int age;
    std::string name;

    Dog(int age, std::string name) {
        this->age = age;
        this->name = name;
    }

    Dog() {
        this->age = 0;
        this->name = "";
    }

};

int main()
{
   Animals anm[10];
   anm[0]=Cat();
   anm[1]=Dog();
   std::cout<<anm[1].age;
}

Ответы (2 шт):

Автор решения: Harry

Вообще-то странное решение - почему бы не вынести общее поле age (как и name) в базовый класс?

Тем более что при присваивании

anm[0]=Cat();

происходит срезка, и поля эти остаются "за бортом".

Если позарез требуется такое странное решение - работайте через указатели, с приведением типов. Типа

Animals* anm[10];
anm[0]= new Cat();
anm[1]= new Dog();
std::cout<<((Dog*)anm[1])->age;

Примерно так. Но все это говорит о совершенно непродуманном проектировании...

Я бы ваш простейший пример делал примерно так:

#include <string>
#include <iostream>
#include <iomanip>

using namespace std;

class Animal{
public:
    Animal(int age = 0, const char * name = ""):age(age),name(name){}

    virtual string get_name() const = 0;

protected:
    int age;
    string name;
};

class Cat: public Animal {
public:
    Cat(int age=0, const char* name = ""):Animal(age, name)
    {
    }
    virtual string get_name() const
    {
        return "Cat " + name;
    }
};

class Dog: public Animal {
public:
    Dog(int age=0, const char* name = ""):Animal(age, name)
    {
    }
    virtual string get_name() const
    {
        return "Dog " + name;
    }
};

int main()
{
   Animal* anm[2];
   anm[0] = new Cat(1,"Vaska");
   anm[1] = new Dog(2,"Sharik");

   cout << anm[0]->get_name() << endl;;
   cout << anm[1]->get_name() << endl;;
}
→ Ссылка
Автор решения: AR Hovsepyan

Подход тут может быть самым разнообразным. Если классы ничем не будут отличаться, то можно просто указать тип животного. Для конкретно данного случая, я бы пользовался этим подходом:

enum class Type { cat, dog }; //тип животного(известен при рождении)
class Animals {     
public:       
    Animals(Type t = Type::cat, const unsigned age = 1)
        : type(t), age(age), name(t == Type::cat ? "cat " : "dog ") {}
    //имя придается после рождения
    void set_name(const string& s) { name += s; }
    string get_name() const { return name; }
    unsigned age;
private:
    std::string name = "";
    Type type;    
};

int main() {  
    Animals anm[10];    
    anm[0] = Animals(Type::dog, 5);
    anm[0].set_name("sharik");    
    std::cout << anm[0].get_name() << ' ' << anm[0].age
             << '\n' << anm[1].get_name() << ' ' << anm[1].age;     
    return 0;
}
→ Ссылка