Чистый виртуальный метод VS. Указатель функции - PullRequest
2 голосов
/ 01 февраля 2009

Недавно я проектировал библиотеку классов Thread, я создал абстрактный класс Thread, как показано ниже:

class Thread {
public:
    run() { /*start the thread*/ }
    kill() { /*stop the thread*/ }
protected:
    virtual int doOperation(unsigned int, void *) = 0;
};

Классы реальных потоков наследуют этот абстрактный класс и реализуют метод doOperation в своей собственной логике, что-то похожее на Pattern Pattern .

Проблема в том, что я полагаюсь на внутреннюю библиотеку C, которая определяет запуск потока в следующей функции:

int startThread(char* name, (int)(*)(unsigned int, void*), int, int, int, void*);

Как вы можете видеть; второй параметр - это указатель на цикл потока (основная функция), и здесь возникает проблема; так как я использую эту C-функцию для запуска потока в методе run, я передаю адрес doOperation второму параметру, и это невозможно сделать из-за несоответствия типов.

Я пытался использовать reinterpret_cast для возврата указателя, но I ISO-C ++ запрещает возвращать указатель неинициализированного члена функции. Я не знаю, как преодолеть этот конфликт, использование статического метода - единственное решение, которое я предполагаю, но оно взрывает мой шаблон проектирования!

1 Ответ

7 голосов
/ 01 февраля 2009

Во-первых, обязательно прочитайте ссылку, предоставленную Майклом Берром, так как она содержит полезную информацию. Тогда вот псевдокод C ++ ish для него:

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 для передачи всего этого указателя в doOperation. Обратите внимание, что детали void * скрыты от пользователей вашего класса, что приятно.

...