Альтернативы абстрактному базовому классу для хранения

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

Короче говоря, я не хочу этого:

class Animal
{
public:
    virtual void noise() const = 0;
};

class Dog : public Animal
{
public:
    virtual void noise() override const {std::cout<<"Woof!\n";};
};

class Cat : public Animal
{
public:
    virtual void noise() override const {std::cout<<"Meow!\n";};
};

//...

std::vector<Animal*> animals;

Я хочу что-то вроде этого:

class Dog
{
public:
    void noise() const {std::cout<<"Woof!\n";};
};

class Cat
{
public:
    void noise() const {std::cout<<"Meow!\n";};
};

//...

std::vector<*Things that have noise()*> animals;

1 ответ

В вашем примере я не могу вам помочь, но для классов с членами данных, здесь есть оптимизация.

Давайте предположим, что мы хотим создать игру пули-ада.

В наивном подходе нам нужен класс Bullet:

class Bullet {
public:
    void draw(Renderer& r);
    virtual void update_logic(float delta);
    void run_physics();
protected:
    float vx, vy; //velocity
private:
    float x, y; //position
    //...
};

Итак update_logic метод будет вызван, чтобы установить скорость пули, затем run_physics применит эту скорость к позиции.

Модификация логики требует полиморфизма, поэтому ваша коллекция становится std::vector<Bullet*> (или же std::vector<std::unique_ptr<Bullet> > в современном с ++).

Затем, в вашем основном цикле, сначала вы обновляете логику, затем физику, затем вы рисуете свои пули.

Конечно, это неэффективно из-за разыменования указателя, vtables и т. Д.

Вместо этого вы можете:

class Bullet {
public:
    void draw(Renderer& r);
    void update_logic(float delta) { logic->update(delta); };
    void run_physics();
    void setVelocity(float, float);
    void setLogic(BulletLogic*);
private:
    float x, y, vx, vy;
    BulletLogic* logic;
};

Так что теперь вы можете использовать std::vector<Bullet>и перенаправление будет происходить только при обновлении логики, но не при запуске физики или рисовании маркера.

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