Metodo virtuale puro VS. Puntatore a funzione
-
20-08-2019 - |
Domanda
Recentemente ho progettato una libreria di classi Thread, ho creato una classe astratta Thread come la seguente:
class Thread {
public:
run() { /*start the thread*/ }
kill() { /*stop the thread*/ }
protected:
virtual int doOperation(unsigned int, void *) = 0;
};
Le classi di thread reali erediteranno questa classe astratta e implementerebbero il metodo doOperation
nella sua logica, qualcosa di simile a Modello di strategia .
Il problema è che mi affido a una libreria back-end C che definisce l'esecuzione del thread nella seguente funzione:
int startThread(char* name, (int)(*)(unsigned int, void*), int, int, int, void*);
Come puoi vedere; il secondo parametro è un puntatore a funzione del loop del thread (funzione principale), ed ecco il problema; poiché utilizzo questa funzione C per avviare il thread nel metodo run
, passo l'indirizzo di reinterpret_cast
al secondo parametro e ciò non può essere fatto a causa della mancata corrispondenza del tipo.
Ho provato a usare <=> per restituire un puntatore, ma I ISO-C ++ proibisce di restituire un puntatore di membro di funzione non inizializzato. Non so come superare questo conflitto, l'uso di un metodo statico è l'unica soluzione che immagino, ma fa esplodere il mio modello di progettazione!
Soluzione
Per prima cosa, assicurati di leggere il link fornito da Michael Burr, in quanto contiene buone informazioni. Quindi, ecco lo pseudo-codice ish C ++ per esso:
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 ......;
};
L'idea è che doOperation, essendo una funzione membro di Thread, non ha bisogno di un contesto vuoto *, puoi semplicemente mantenere qualunque cosa passi come contesto nell'oggetto stesso. Pertanto, è possibile utilizzare il puntatore vuoto per passare l'attuatore questo puntatore a doOperation. Nota che i dettagli del void * sono nascosti agli utenti della tua classe, il che è carino.