Гнучкі альтернативи багатьом багатьом малим поліморфним класам (для використання як властивостей, повідомлень чи подій) C ++


9

У моїй грі є два заняття, які справді корисні, але повільно стають болем. Повідомлення та властивість (властивість по суті є компонентом).

Вони обидва походять від базового класу і містять статичний ідентифікатор, щоб системи могли звертати увагу лише на ті, які вони хочуть. Це дуже добре працює ... за винятком ...

По мірі розширення гри я постійно створюю нові типи повідомлень та типи властивостей. Кожен раз, коли мені потрібно записати 2 файли (hpp та cpp) та тонну панелі котлів, щоб отримати по суті classID та один або два стандартних типи даних або покажчик.

Починати перетворювати та випробовувати нові ідеї потрібно справжньою справою. Я хочу, коли я хочу створити нове повідомлення або тип властивості, я можу просто ввести щось на зразок

ShootableProperty:  int gunType, float shotspeed;

ItemCollectedMessage:  int itemType;

замість створення файлу заголовка та cpp, написання конструктора, включаючи батьківський клас тощо, тощо.

Це приблизно 20 - 40 рядків (включаючи охорону, і все), щоб зробити те, що логічно - це 1 або 2 рядки.

Чи існує якась схема програмування, щоб обійти це?

А як щодо сценаріїв (про які я нічого не знаю) ... чи є спосіб визначити купу класів, які майже однакові?


Ось як виглядає один клас:

// Velocity.h

#ifndef VELOCITY_H_
#define VELOCITY_H_

#include "Properties.h"

#include <SFML/System/Vector2.hpp>

namespace LaB
{
namespace P
{

class Velocity: public LaB::Property
{
public:
    static const PropertyID id;

    Velocity(float vx = 0.0, float vy = 0.0)
    : velocity(vx,vy) {}
    Velocity(sf::Vector2f v) : velocity(v) {};

    sf::Vector2f velocity;
};

} /* namespace P */
} /* namespace LaB */
#endif /* LaB::P_VELOCITY_H_ */



// Velocity.cpp

#include "Properties/Velocity.h"

namespace LaB
{
namespace P
{

const PropertyID Velocity::id = Property::registerID();

} /* namespace P */
} /* namespace LaB */

Все це лише для 2D вектора та ідентифікатора, що говорить про очікування 2D вектора. (Звичайно, деякі властивості мають складніші елементи, але це одна і та ж ідея)


3
Погляньте на це, це може вам допомогти. gameprogrammingpatterns.com/type-object.html

1
Все це виглядає так, що шаблони можуть допомогти, тільки не при статичній ініціалізації. У цьому випадку це, безумовно, може бути набагато простіше, але важко сказати без додаткової інформації про те, що ви хочете робити з цими ідентифікаторами і чому ви взагалі використовуєте спадщину. Використання публічної спадщини, але без віртуальних функцій, безумовно, кодовий запах ... Це не поліморфізм!
ltjax

Ви знайшли сторонню бібліотеку, яка реалізує її?
Борис

Відповіді:


1

C ++ є потужним, але є багатослівним . Якщо ви хочете, це безліч малих поліморфних класів, які різняться, то так, для декларування та визначення потрібно буде багато вихідного коду. Насправді тут нічого не робити.

Тепер, як сказав ltjax, те, що ви робите тут, не є саме поліморфізмом , принаймні для коду, який ви надали. Я не бачу загального інтерфейсу, який би приховував конкретну реалізацію підкласів. За винятком ідентифікатора класу, але це справді зайве з реальним ідентифікатором класу: це ім'я. Здається, це лише купа занять, що містять деякі дані, нічого насправді не складного.

Але це не вирішує вашу проблему: ви хочете створити безліч повідомлень і властивостей з найменшою кількістю коду. Менше коду означає менше помилок, тому це розумне рішення. На жаль для вас немає єдиного рішення. Важко сказати, що найбільше відповідає вашим потребам, не знаючи точно, що ви маєте намір робити з цими повідомленнями та властивостями . Тож дозвольте лише викласти ваші варіанти:

  1. Використовуйте шаблони C ++ . Шаблони - це прекрасний спосіб дозволити компілятору "написати код" для вас. Це стає все більш помітним у світі C ++, оскільки мова розвивається для їх кращої підтримки (наприклад, тепер ви можете використовувати змінну кількість параметрів шаблону ). Існує ціла дисципліна, присвячена автоматизованому генеруванню коду за допомогою шаблонів: метапрограмування шаблонів . Проблема в тому, що це важко. Не чекайте, що непрограмісти зможуть самостійно додавати нові властивості, якщо ви плануєте використовувати таку методику.

  2. Використовуйте набили оскому макроси C . Це стара школа, її легко зловживати і схильна до помилок. Їх також дуже просто створити. Макроси - це просто прославлені копії-пасти, виконані препроцесором, тому вони насправді цілком підходять для створення тонн речей, які майже не відрізняються з невеликими варіаціями. Але не сподівайтеся, що інші програмісти полюблять вас за їх використання, оскільки макроси часто використовуються для приховування недоліків у загальному дизайні програми. Однак іноді вони корисні.

  3. Інший варіант - використовувати зовнішній інструмент для створення коду для вас. Про це вже згадувалося в попередній відповіді, тому я не буду на цьому розширюватись.

  4. Є й інші мови, які є менш дослівними і дозволять вам легше створювати класи. Тож якщо у вас вже є прив'язки сценарію (або ви плануєте їх мати), визначення цих класів у сценарії може бути варіантом. Доступ до них через C ++ буде досить складним, і ви втратите більшу частину користі від спрощеного створення класів. Тож це, мабуть, життєздатно лише якщо ви плануєте робити більшу частину своєї логіки гри на іншій мові.

  5. І нарешті, але не в останню чергу, слід розглянути можливість використання керованої даних конструкції . Ви можете визначити ті "класи" у простих текстових файлах, використовуючи макет, аналогічний тому, який ви запропонували самі. Вам доведеться створити спеціальний формат і аналізатор для нього або скористатися одним із декількох уже доступних варіантів (.ini, XML, JSON і багато чого іншого). Потім на стороні C ++ вам потрібно буде створити систему, яка підтримує колекцію цих різних видів об’єктів. Це майже еквівалентно сценарному підходу (і, ймовірно, вимагає ще більшої роботи), за винятком того, що ви зможете більш точно підлаштувати його під ваші потреби. А якщо зробити це досить просто, непрограмісти можуть створити нові речі самостійно.


0

Як щодо інструменту генерації коду, який вам допоможе?

Наприклад, ви можете визначити тип свого повідомлення та членів у невеликому текстовому файлі, а інструмент для кодового генеалогічного аналізу проаналізувати його та записати всі файли C ++ на панелі котлів як крок попереднього збирання.

Існують існуючі рішення, такі як ANTLR або LEX / YACC, і було б непросто прокрутити своє, залежно від складності ваших властивостей та повідомлень.


Просто альтернатива підходу LEX / YACC, коли мені доводиться генерувати дуже схожі файли з незначними модифікаціями, я використовую простий і невеликий сценарій python та файл шаблону коду C ++, що містить теги. Сценарій python шукає ці теги в шаблоні, замінюючи їх репрезентативними лексемами створеного елемента.
переможець

0

Раджу вивчити протоколи буферів протоколів Google ( http://code.google.com/p/protobuf/ ). Вони є дуже розумним способом обробки загальних повідомлень. Вам просто потрібно вказати властивості в структурі-подібному шаблоні, і генератор коду виконає всю роботу з генерування класів для вас (Java, C ++ або C #). Усі генеровані класи мають текстові та двійкові аналізатори, що робить їх корисними як для ініціалізації текстових повідомлень, так і для серіалізації.


Мій центр обміну повідомленнями є основним моєю програмою - чи знаєте ви, чи буфери протоколів мають великі накладні витрати?
Брайан

Я не думаю, що вони несуть великі накладні витрати, оскільки API - це лише клас Builder для кожного повідомлення та клас для самого повідомлення. Google використовує їх для ядра своєї інфраструктури. Наприклад, суб'єкти Google App Engine всі перетворюються на буфери протоколів до збереження. Якщо ви сумніваєтесь, раджу застосувати тест порівняння між вашою поточною реалізацією та буферами протоколів. Якщо ви вважаєте, що накладні витрати прийнятні, використовуйте їх.
dsilva.vinicius
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.