Я пытаюсь написать слой абстракции, чтобы мой код работал на разных платформах. Позвольте мне привести пример для двух классов, которые я в конечном счете, хотят использовать в коде высокого уровня:Дизайн шаблона: C++ Уровень абстракции
class Thread
{
public:
Thread();
virtual ~Thread();
void start();
void stop();
virtual void callback() = 0;
};
class Display
{
public:
static void drawText(const char* text);
};
Моя беда в том: Какой дизайн шаблон можно использовать, чтобы досыта код низкого уровня в реализации? Вот мое thoughs и почему я не думаю, что они являются хорошим решением:
В теории нет никаких проблем в том, вышеуказанных сидячих определениях в
highLevel/thread.h
и конкретную реализации платформы сидеть вlowLevel/platformA/thread.cpp
. Это низкозатратное решение, которое разрешено во время соединения. Единственная проблема заключается в том, что реализация на низком уровне не может добавлять к ней какие-либо переменные-члены или функции-члены. Это делает невозможным реализацию определенных вещей.Выходом было бы добавить это определение (в основном Pimpl-Idiom):
class Thread { // ... private: void* impl_data; }
Теперь код низкого уровня может иметь свои собственные структуры или объекты, хранящиеся в указателе ничтожной. Беда здесь в том, что ее уродливые, чтобы читать и мучить программу.
Я мог бы сделать
class Thread
чистой виртуальной и реализовать низкоуровневую функциональность, наследуя от нее. Код высокого уровня может получить доступ к реализации низкого уровня, вызывая функцию фабрики, как это:// thread.h, below the pure virtual class definition extern "C" void* makeNewThread(); // in lowlevel/platformA/thread.h class ThreadImpl: public Thread { ... }; // in lowLevel/platformA/thread.cpp extern "C" void* makeNewThread() { return new ThreadImpl(); }
Это было бы достаточно аккуратным, но он не для статических классов. Мой уровень абстракции будет использоваться для аппаратного обеспечения и операций ввода-вывода, и мне бы очень хотелось иметь
Display::drawText(...)
вместо того, чтобы переносить указатели на один классDisplay
.Другой вариант - использовать только функции стиля С, которые могут быть разрешены во время соединения, например,
extern "C" handle_t createThread()
. Это легко и удобно для доступа к низкоуровневому оборудованию, которое есть только один раз (например, дисплей). Но для чего-то, что может быть несколько раз (блокировки, потоки, управление памятью), я должен носить с собой ручки в моем коде высокого уровня, который является уродливым или имеет класс обертки высокого уровня, который скрывает ручки. В любом случае у меня есть накладные расходы, связанные с необходимостью связывать ручки с соответствующими функциями как на высоком уровне, так и на стороне низкого уровня.Моя последняя мысль - гибридная структура. Pure C-style
extern "C"
функции для низкоуровневого материала, который есть только один раз. Заводские функции (см. 3.) для вещей, которые могут быть там несколько раз. Но я боюсь, что что-то гибридное приведет к непоследовательному, нечитаемому коду.
Я был бы очень признателен за советы по дизайну образцов, соответствующих моим требованиям.
Не читал весь ваш вопрос еще. Но C++ имеет уровень абстракции для потоков с C++ 11. – StoryTeller
Я работаю над встроенной целью с FreeRTOS, поддерживая материал для потоковой передачи. Другая платформа - это эмуляция на базе компьютера для упрощения разработки кода высокого уровня. Я не думаю, что C++ 11 поддерживает этот сценарий. – LoveDaOOP