Почему меняется тип объекта? (виртуальная функция)

90
22 апреля 2022, 00:10

Есть родительский класс command и два дочерних - movement и root. Заголовочный файл:

class Command {
public:
    static const int TIME_MIN = 0;
    static const int TIME_DEFAULT = 0;
    int getTime() const;
    void setTime(const int time);
    virtual void setValue(const int value);
    virtual int getValue() const;
protected:
    int time_current;
};
class Movement : public Command {
public:
    static const int SPEED_MAX = 100;
    static const int SPEED_DEFAULT = 0;
    static const int SPEED_MIN = 0;
    Movement();
    Movement(const int time, const int speed);
    Movement(const Movement &car);
    virtual void setValue(const int value) override;
    virtual int getValue() const override;
private:
    int speed_current;
};
class Root : public Command {
public:
    static const int RADIUS_MAX = 100;
    static const int RADIUS_MIN = -100;
    static const int RADIUS_DEFAUT = 0;
    Root(const int time, const int radius);
    Root();
    virtual void setValue(const int value) override;
    virtual int getValue() const override;
private:
    //+ means right, - means left; by default right with radius +
    int radius_current;
};

Реализация виртуальных функций:

int Command::getValue() const {
    return 99;
}
void Command::setValue(const int value) {
};
int Movement::getValue() const {
    return speed_current;
}
int Root::getValue() const {
    return radius_current;
}
void Movement::setValue(const int value) {
    if (value >= SPEED_MAX)
        speed_current = SPEED_MAX;
    else if (value <= SPEED_MIN)
        speed_current = SPEED_MIN;
    else
        speed_current = value;
}
void Root::setValue(const int value) {
    if (value >= RADIUS_MAX)
        radius_current = RADIUS_MAX;
    else if (value <= RADIUS_MIN)
        radius_current = RADIUS_MIN;
    else
        radius_current = value;
}

Объекты класса Command хранятся в очереди:

class CarCollection {
private:
    struct ListElement {
        Command data;
        ListElement *next;
    };
public:
    void add(const Command &obj); // метод добавления
    ListElement *first;
    ...
    ...
    ...

Само добавление в очередь:

void CarCollection::add(const Command &d) {
    // добавление элемента в очередь
    ListElement* cur = first;
    while(cur->next) cur = cur->next;
    cur->data = d; //тип movement -> тип command
    cur->next = new ListElement();
    this->size++;
}

Проблема в том, что, если я создаю объект дочернего класса и хочу добавить его в коллекцию, то на строчке

cur->data = d; //тип movement -> тип command

меняется тип объекта на родительский и я теряю информацию из дочернего класса. Сам вызов:

CarCollection queue;
Movement car(58,50);
queue.add(car)

Что я делаю неправильно? Большое спасибо

Answer 1

Это эффект срезки - вы объявили, что в структуре хранится родительский объект, вот при копировании потомок и урезается до родителя. Просто подумайте - куда, например, копировать лишние поля потомка (по сравнению с предком), если размер места в структуре это просто не позволяет?

Храните указатели на объекты - и все будет хорошо. Указатели - они все одного размера :) Сказал бы - храните ссылки, но это просто так, без прокси-класса, не сработает, так что проще хранить указатели.

READ ALSO
Ряды в C++, помогите с задачкой, пожалуйста

Ряды в C++, помогите с задачкой, пожалуйста

Не могу понять, как можно реализовать это (если можно, попробуйте объяснить мне, как все нужно делать):

115
Почему зацикливается программа на C++?

Почему зацикливается программа на C++?

Дана строка SВывести символ L, который встречается наибольшее число раз

169
Проблема с виртуальными методами

Проблема с виртуальными методами

В ООП я новичокДошел до наследования

185