шаблоны проектирования — встроенный c ++: динамическая типизация без динамического выделения?

Вот моя проблема, упрощенно:

  • У меня есть код на C / C ++, C для служб, C ++ для обработки.
  • У меня есть интерфейс в C, который возвращает структуру RawData, которая содержит информацию, которая циклически обновляется.
enum AnimalType_t
{
СОБАКА = 0,
GREY_HOUND = 1,
IMMORTAL_JELLYFISH = 2,
};
struct RawData_t
{
в возрасте;
AnimalType_t typeOfAnimal;
};

RawData_t GetMyCurrentRawData (); // возвращает текущие необработанные данные
bool IsDataReady (); // возвращает true, если данные готовы, иначе false
  • У меня виртуальная мама класс «Зверь»
класс животных
{
общественности:
виртуальное животное ();
виртуальный ~ Animal ();
int GetType () {return rawAttributes.typeOfAnimal; }; // единственная реализация для всех детей
virtual int GetAge () {return rawAttributes.age; }; // для реализации в дочернем классе
виртуальная пустота UpdateAge () {rawAttributes.age ++; }; // для реализации в дочернем классе
virtual int GetNumberOfLegs () = 0; // для реализации в дочернем классе
частный:
RawData_t rawAttributes;
}
  • У меня есть известный список животных, которые наследуются от материнского класса.
класс собака: общественное животное
{
общественности:
Собака (RawData rawData): Животное (rawData) {};
int GetNumberOfLegs () {return 4;};
};

класс GreyHound: публичный пёс
{
общественности:
GreyHound (RawData rawData): Dog (rawData) {};
};

класс ImmortalJellyFish: общедоступное животное
{
общественности:
ImmortalJellyFish (RawData rawData): Animal (rawData) {};
int GetNumberOfLegs () {return 0;};
void UpdateAge () {return;} переопределить;
};
  • У меня есть класс «Здание», в котором есть только одно животное, но я не знаю его тип, когда создаю экземпляр здания.
Здание класса
{
общественности:
Строительство(){};
// простите за длинную очередь, но вы поняли идею ...
int Display (void) {if (IsDataReady ()) DisplayOnScreen ("Это животное (" + animal_m.GetType () + ") имеет" + animal_m.GetNumberOfLegs () + "ноги и является" + animal_m.GetAge () + ") лет \ n ";};
int Live (void) {currentDiagCode_m.UpdateAge ();};

частный:
auto animal_m; // ?? не работает
};

статический строительный загон;
статичное здание фермы;

void Buildings_Step (void)
{
paddock.Live ();
paddock.Display ();
farm.Live ();
farm.Display ();
}

Вот где я борюсь:

  • выделить память для животного в Здании, не зная его типа во время создания объекта,
  • тип и атрибуты животного могут меняться циклически
    Другими словами: возможна ли динамическая типизация со статическим размещением?
    Тогда как я могу вызвать эти экземпляры, чтобы был вызван правильный метод?

Вот мои ограничения:

  • Встроенная система
  • нет динамического выделения памяти

Я хоть о:

  • шаблон фабричного дизайна с unique_ptr, который прекрасно работает !!! … но, в куче 🙁
  • Объектный пул?
  • динамическая типизация: но без динамического выделения это невозможно?

Есть ли дизайн / модель, которая может удовлетворить мои потребности?

Спасибо!

1

Решение

В C ++ выделение памяти и существование объекта — это две разные концепции, хотя в большинстве ситуаций вы будете обрабатывать обе вместе. В вашем случае, однако, вы можете явно разделить два:

  1. Создайте достаточно памяти для любого объекта:

    char buf[N];    // N >= sizeof(T) for all T in your hierarchy
    
  2. Чтобы создать животное:

    new (buf) GreyHound(args);
    
  3. Чтобы уничтожить существующее животное (и освободить место для другого):

    reinterpret_cast<Animal*>(buf)->~Animal();
    

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

Есть еще кое-что: ваша память также должна быть правильно выровнена для всех типов, которые вы создаете в ней. Вы можете использовать некоторые вспомогательные черты библиотеки, такие как std::aligned_storage или же std::aligned_union чтобы упростить вычисления, хотя вам, вероятно, все равно придется проделать небольшую работу для вычисления как размера, так и выравнивания.


В качестве совершенно отдельной альтернативы вы можете отказаться от полиморфной иерархии классов и использовать std::variant вместо. Это концептуально схожий, но несколько иной подход к реализации. Причина, по которой это концептуально схоже, заключается в том, что у вас есть ограниченный набор типов, поэтому вам не нужен полиморфизм для обработки произвольно, неизвестно производные типы во время выполнения.

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]