Как сохранить дочерние классы в векторе и переопределить родительскую функцию

Я пытаюсь закодировать серию js super-mario с отличного канала YouTube «метод метамфетамина» на С++ и SDL2.

Теперь я застрял на Эпизоде ​​04 - https://thewikihow.com/video_1rBOUyRGQuU

Я пытаюсь создать класс Entity, который имеет вектор класса Trait. Я хочу создать много разных классов, которые наследуются от Trait и сохранят их в векторе. Я хочу вызвать функцию обновления подклассов, а не исходную функцию обновления признаков.

// -- Entity.h -----------------------------------

class Entity {
private:
    Vec2 vel;
    std::vector<Trait*> traits;

public:
    Vec2 pos;
    // Constructor & Destructor
    Entity(void);   
    ~Entity(void);

    void addTrait(Trait* nTrait);

    void update();
};

// -- Entity.cpp -----------------------------------

void Entity::addTrait(Trait* newTrait) { 
    this->traits.push_back( newTrait );
}

void Entity::update() {

    for ( Trait* trait : this->traits ) {
        trait->update(  );
    }    
}

// -- Trait.h -----------------------------------
class Trait {
private:
    std::string name;
public:
    // Constructor & Destructor
    Trait(std::string aname );
    ~Trait(void);

    void update( void );
};
// -- Trait.cpp -----------------------------------
void Trait::update(  ) {
    printf("Trait update\n");
}

И подклассы Velocity.h от Trait

// -- Velocity.h -----------------------------------
class Velocity : public Trait {
private:
public:
    // Constructor & Destructor
    Velocity(std::string aname);
    ~Velocity(void);

    void update(Entity *entity);
};
// -- Velocity.cpp -----------------------------------
void Velocity::update(Entity *entity ) {
    printf("Velocity update\n");
    entity->setPos(0, 0);
}

Я пробовал много разных версий и получал разные ошибки. Теперь у меня это работает, но когда я добавляю свойство скорости к объекту и вызываю метод обновления объекта (который перебирает все признаки), только функция обновления вызывается из родительского класса признаков (который печатает «Обновление признаков» и не "обновление скорости").

main.cpp

    Entity *mario = new Entity();

    mario->setPos( 64, 180 );
    mario->setVel(  2, -2 );

    Velocity* velTrait = new Velocity("velocity");
    mario->addTrait(velTrait);

    mario->update();

И второй вопрос заключается в том, что я хочу дать функции обновления скорости указатель на объект, чтобы я мог изменить положение объекта и т. д.

Держитесь подальше от метода кристаллического метамфетамина.

user4581301 08.05.2019 20:03

@xpnimi Рассматривали ли вы на самом деле учусь C++ (это займет пару лет), а не просто следуя случайным руководствам на YouTube?

Jesper Juhl 08.05.2019 20:13

@JesperJuhl Я пытаюсь изучать C++ на стороне, и я думаю, что это хорошее упражнение для переноса кода с одного языка на другой - это вовсе не случайное видео yt. Но все равно спасибо.

xpnimi 08.05.2019 20:54
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
49
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

I want to create many different classes which inherit from Trait and store them in the vector. I want to call the subclasses update function and not the original Trait update function.

Чтобы получить то, что вы хотите, используйте метод virtual:

virtual void update( void );

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

Да, я пробовал это, но куда именно идет ключевое слово virtual? только для обновления Trait.h??

xpnimi 08.05.2019 20:04

если я добавлю virtual к функции обновления признаков, функция обновления скорости все равно не будет вызываться.

xpnimi 08.05.2019 20:06

Чтобы это заработало, функция обновления скорости должна быть объявлена ​​так же, как и функция скорости трейтов.

xpnimi 08.05.2019 20:19

@xpnimi да, это так. А в C++11 и более поздних версиях вы можете (и должны) пометить метод класса-потомка как override, чтобы позволить компилятору проверить, действительно ли метод-потомок переопределяет метод базового класса или нет: void update(void) override; Без override такая проверка не выполняется. , вот почему вы пропустили эту ошибку, когда впервые добавили virtual

Remy Lebeau 08.05.2019 20:31

@RemyLebeau, как я могу передать сущность любой черте вектора черт внутри функционального цикла обновления сущности? Если я добавлю Entity.h в Trait.h, я получу довольно много ошибок, и я думаю, что это конфликт, потому что оба класса ссылаются на себя...

xpnimi 08.05.2019 20:47

@xpnimi Вам действительно придется изменить метод Trait::update(), чтобы он принимал Entity* в качестве входных данных, чтобы Velocity::update() мог сделать то же самое. Но затем вы сталкиваетесь с классической проблемой циклических ссылок, которая решается с помощью указателей (которые у вас уже есть) и предварительные заявления (именно этого вам не хватает).

Remy Lebeau 08.05.2019 21:12

@RemyLebeau Спасибо - это очень помогло, все заработало!

xpnimi 09.05.2019 16:34

Другие вопросы по теме