встроенный c ++: динамическая типизация без динамического выделения? - PullRequest
0 голосов
/ 02 декабря 2018

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

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

    RawData_t GetMyCurrentRawData();//returns the current raw data
    bool      IsDataReady(); //returns true if data is ready, false otherwise
  • У меня есть виртуальный родительский класс "Animal"
    class Animal
    {
    public:
        virtual Animal();
        virtual ~Animal();
        int GetType() { return rawAttributes.typeOfAnimal; };   //the only implementation for all children
        virtual int GetAge() { return rawAttributes.age; };     //to be implemented in the child class
        virtual void UpdateAge() { rawAttributes.age++; };  //to be implemented in the child class
        virtual int GetNumberOfLegs() = 0;                      //to be implemented in the child class
    private:
        RawData_t rawAttributes;
    }
  • У меня есть известный список животных, которые наследуются от материнского класса.
    class Dog : public Animal
    {
    public:
        Dog(RawData rawData):Animal(rawData){};
        int GetNumberOfLegs() {return 4;};                  
    };

    class GreyHound : public Dog
    {
    public:
        GreyHound(RawData rawData):Dog(rawData){};
    };

    class ImmortalJellyFish : public Animal
    {
    public:
        ImmortalJellyFish(RawData rawData):Animal(rawData){};
        int GetNumberOfLegs() {return 0;};      
        void UpdateAge() { return;} override;
    };
  • У меня есть класс "Строительство", в котором есть один, только один,животное, но я не знаю его тип, когда создаю экземпляр здания.
    class Building
    {
    public:
        Building(){};
        //sorry for the long line, but you get the idea...
        int Display(void){if(IsDataReady()) DisplayOnScreen("This animal ( "+ animal_m.GetType()+") has " + animal_m.GetNumberOfLegs() + "legs and is " + animal_m.GetAge() + " years old\n";};
        int Live(void){currentDiagCode_m.UpdateAge();};

    private:
        auto                        animal_m; //?? not working
    };

    static Building paddock;
    static Building farm;

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

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

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

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

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

Я думаю о:

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

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

Спасибо!

1 Ответ

0 голосов
/ 02 декабря 2018

В 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.Это концептуально схожий, но несколько иной подход к реализации.Причина, по которой это концептуально схоже, заключается в том, что у вас ограниченный набор типов, поэтому вам не нужен полиморфизм для обработки произвольных, неизвестных производных типов во время выполнения.

...