Чистый виртуальный метод VS.Указатель на функцию
-
20-08-2019 - |
Вопрос
Недавно я разрабатывал библиотеку классов Thread, я создал абстрактный класс Thread, подобный следующему:
class Thread {
public:
run() { /*start the thread*/ }
kill() { /*stop the thread*/ }
protected:
virtual int doOperation(unsigned int, void *) = 0;
};
Классы реальных потоков унаследовали бы этот абстрактный класс и реализовали doOperation
метод по своей собственной логике, что-то похожее на Шаблон стратегии.
Проблема в том, что я полагаюсь на серверную библиотеку C, которая определяет запуск потока в следующей функции:
int startThread(char* name, (int)(*)(unsigned int, void*), int, int, int, void*);
Как вы можете видеть;второй параметр - это указатель функции на цикл потока (основная функция), и вот в чем проблема;поскольку я использую эту C-функцию для запуска потока в run
метод, я передаю адрес doOperation
ко второму параметру, и это невозможно сделать из-за несоответствия типов.
Я пытался использовать reinterpret_cast
чтобы вернуть указатель, но I ISO-C ++ запрещает возвращать указатель на неинициализированный элемент функции.Я не знаю, как преодолеть этот конфликт, использование статического метода - единственное решение, я думаю, но это разрушает мой шаблон проектирования!
Решение
Во-первых, обязательно прочтите ссылку, предоставленную Майклом Берром, поскольку она содержит полезную информацию.Тогда вот псевдокод на C ++ для этого:
int wrapperDoOperation(int v, void *ctx)
{
Thread *thread = (Thread *)ctx;
return thread->doOperation(v);
}
class Thread {
public:
run() {
startThread("bla", wrapperDoOperation, bla, bla, bla, (void *)this);
}
kill() { /*stop the thread*/ }
protected:
virtual int doOperation(unsigned int) = 0;
friend wrapperDoOperation ......;
};
Идея заключается в том, что doOperation, будучи функцией-членом Thread, не нуждается в контексте void *, вы можете просто сохранить все, что вы передали бы в качестве контекста в самом объекте.Следовательно, вы можете использовать указатель void для передачи фактического значения этого указателя в doOperation.Обратите внимание, что сведения о void * скрыты от пользователей вашего класса, что приятно.