Как предлагается в другом ответе и комментариях, я бы не советовал использовать динамическое распределение памяти c во встроенных средах. Очень важно иметь детерминированное поведение в отношении вашей ограниченной памяти. При работе с голым металлом действительно трудно / невозможно отловить исключения из памяти. Использование RTOS даст вам немного больше гибкости, но не намного.
Однако это возможно. Чтобы сделать вашу программу полиморфизмом без динамического выделения памяти c, вы можете добиться этого, используя union для C ++ 11 или вариант для C ++ 17. Вы можете использовать их для статического выделения памяти и последующей инициализации реального объекта. Для поддержки нескольких объектов вы можете использовать массив ограниченного размера.
В следующем примере создается массив объединений stati c для вашего интерфейса. Заводская функция инициализирует память в объединении. Функция очистки вызывает деструктор для очистки объединения.
#include <array>
template<int SIZE>
class Buffer
{
private:
union DataUnion
{
// These are required. Please check the documenation of unions.
DataUnion() {};
~DataUnion() {};
// Actual data in the union.
InterfaceA a;
InterfaceB b;
};
std::array<DataUnion, SIZE> dataArray;
public:
Buffer() = default;
~Buffer() = default;
// This is the interface factory
Interface* SelectInterface(int type)
{
// This function will return null when there is no space. You can easily deal with this
// compared to an exception.
Interface* pointer = nullptr;
// First check there is space in the array
// Pseudo code
if(dataArray.has_space())
{
// Pseudo code to get a free union
DataUnion& union = GetFreeUnion();
if (type == 0)
{
// Initialize the memory in the union to be of type A.
// Use the placement new.
new &(union.a) InterfaceA{};
pointer = &(union.a);
}
else if (type == 1)
{
// Initialize the memory in the union to be of type B.
// Use the placement new.
new &(union.b) InterfaceB{};
pointer = &(union.b);
}
}
return pointer;
}
// After your done with the object you need to clear the memory.
void Clear(Interface* pointer_to_data)
{
// Pseudo code to find the index in the array.
int index = FindIndex(pointer_to_data)
DataUnion& union = dataArray[index];
// Pseudo code to retrieve the type stored at that index.
// You need to keep track of that, which is not in this example.
int type = GetType(index);
// Now call the destructor of the object to clear the union.
if(type = 0)
{
union.a.~InterfaceA();
}
else if(type = 1)
{
union.b.~InterfaceB();
}
// Update the administration that index is free.
}
};
// Define the buffer.
Buffer<10> buffer;
main()
{
// Initiate an instance of a.
Interface* pA = buffer.SelectInterface(0);
if(nullptr != pA)
{
// Do something.
}
// Initiate an instance of b.
Interface* pB = buffer.SelectInterface(1);
if(nullptr != pB)
{
// Do something.
}
// Stop using a.
buffer.Clear(pA);
// And on
}
Существуют ограничения, которые необходимо учитывать:
- InterfaceA, InterfaceB и другие имеют сопоставимый размер. Если у вас есть один производный класс, который будет намного больше, он увеличит распределение памяти.
- У вас должно быть общее представление о том, сколько объектов вам нужно одновременно. Буфер всегда выделяется, даже если вы его не используете.
- Союзы имеют ограничения и нуждаются в особом уходе. Используйте их с умом! Прочитайте документацию и этот пост .
- Вам нужно реализовать код, чтобы отслеживать, какие индексы заняты.
На данный момент я еще не использовал опцию std :: варианта. Я подозреваю это будет проще, поскольку вам не нужно инициализировать и очищать память вручную.
Я надеюсь, что это ответ на ваш вопрос. Да, можно использовать полиморфизм и иметь распределение c.
Если вы ищете дополнительные примеры использования C ++ во встроенном устройстве, вы можете взглянуть на код MBED OS . Я нахожу это очень ясным кодом C ++ (мое мнение), и мне интересно, что ARM, один из крупнейших разработчиков mcu в мире, выбрал C ++ для своего кода.