Méthode virtuelle pure VS. Pointeur de fonction
-
20-08-2019 - |
Question
Récemment, je concevais une bibliothèque de classes Thread. J'ai créé une classe abstraite Thread comme suit:
class Thread {
public:
run() { /*start the thread*/ }
kill() { /*stop the thread*/ }
protected:
virtual int doOperation(unsigned int, void *) = 0;
};
Les classes de thread réelles hériteraient de cette classe abstraite et implémenteraient la méthode doOperation
dans sa propre logique, ce qui est similaire à Modèle de stratégie .
Le problème est que je m'appuie sur une bibliothèque de back-end C qui définit l'exécution du thread dans la fonction suivante:
int startThread(char* name, (int)(*)(unsigned int, void*), int, int, int, void*);
Comme vous pouvez le voir; le second paramètre est un pointeur de fonction sur la boucle du thread (fonction principale), et voici le problème; Étant donné que j'utilise cette fonction C pour démarrer le thread dans la méthode run
, je passe l'adresse de reinterpret_cast
au second paramètre, ce qui est impossible à cause du manque de correspondance de type.
J'ai essayé d'utiliser <=> pour renvoyer un pointeur, mais ISO-C ++ interdit de renvoyer un pointeur de membre de fonction non initialisé. Je ne sais pas comment surmonter ce conflit. La seule solution, je suppose, consiste à utiliser une méthode statique. Cependant, mon schéma de conception explose!
La solution
Tout d’abord, veillez à lire le lien fourni par Michael Burr, car il contient de bonnes informations. Ensuite, voici le pseudo-code ish C ++ pour cela:
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’idée est que doOperation, en tant que fonction membre de Thread, n’a pas besoin d’un contexte vide *, vous pouvez simplement conserver ce que vous transmettez comme contexte dans l’objet même. Par conséquent, vous pouvez utiliser le pointeur vide pour passer l'actuel de ce pointeur à la fonction doOperation. Notez que les détails void * ne sont pas visibles par les utilisateurs de votre classe, ce qui est agréable.