OVH Cloud OVH Cloud

callback de pointeur de fonction membre

1 réponse
Avatar
Michael
Bonjour à tous,

j'ai Windows qui me cause quelques soucis, liés à des callbacks de
fonction.

J'ai par exemple le pointeur de fonction suivant:

typedef void (*LPDXUTCALLBACKFRAMEMOVE)( int i );

J'ai la fonction suivante qui permet d'attribuer un callback:

void WINAPI DXUTSetCallbackFrameMove(LPDXUTCALLBACKFRAMEMOVE pCallback )
{
GetDXUTState().SetFrameMoveFunc(pCallback );
}

Et qui est utilisée

DXUTSetCallbackFrameMove( NewOnFrameMove );

avec

void NewOnFrameMove(int i)
{
//Traitement
}

Seulement j'aimerai incorporer ces fonctions de callback au sein d'une
classe. Seulement bien sûr je ne peux pas attribuer un pointeur de
fonction membre.

J'ai contourné le problème en définissant une fonction membre statique,
qui redirige vers une fonction membre non statique, via un pointeur de la
classe statique.

Je ne pense pas que ce que je viens de dire soit d'une clarté absolue,
donc un petit exemple...

class foo
{
private:
static foo * f;
static void StaticOnFrameMove( int i);

void OnFrameMove(int i);

public:
foo();
}

foo::foo()
{
f = this;
}

void foo::StaticOnFrameMove(int i)
{
f->OnFrameMove(i);
}

void foo::OnFrameMove(int i);
{
//Traitement
}

Est-ce une manière courante de fonctionner? Sinon quelles autres
alternatives s'offrent à moi?

Merci d'avance

Mike

1 réponse

Avatar
James Kanze
Michael wrote:

j'ai Windows qui me cause quelques soucis, liés à des
callbacks de fonction.


J'ai par exemple le pointeur de fonction suivant:


typedef void (*LPDXUTCALLBACKFRAMEMOVE)( int i );


J'ai la fonction suivante qui permet d'attribuer un callback:


void WINAPI DXUTSetCallbackFrameMove(LPDXUTCALLBACKFRAMEMOVE pCallback )
{
GetDXUTState().SetFrameMoveFunc(pCallback );
}


Et qui est utilisée


DXUTSetCallbackFrameMove( NewOnFrameMove );


avec


void NewOnFrameMove(int i)
{
//Traitement
}


Seulement j'aimerai incorporer ces fonctions de callback au
sein d'une classe. Seulement bien sûr je ne peux pas attribuer
un pointeur de fonction membre.


Ni même, si l'API est définie en C, une fonction qui n'est pas
« extern "C" ».

J'ai contourné le problème en définissant une fonction membre
statique, qui redirige vers une fonction membre non statique,
via un pointeur de la classe statique.


Je ne connais pas l'API que tu utilises, mais la plupart de
temps, en plus de l'adresse de la fonction, tu passes un
pointeur à des données (un void*) -- c'est le cas de tous les
interfaces bien conçues, et c'est le cas, d'après ce que j'ai
entendu dire, de la plupart des call-backs dans l'API de
Windows. La solution classique est alors quelque chose du
genre :

extern "C" void /* ou ce qu'il faut, évidemment */
callback( void* p )
{
static_cast< MaClasse* >( p )->laFonctionQuIlFaut() ;
}

On passe alors l'adresse de callback, et l'adresse de l'objet.

(Ce qu'on aimerait, ici, c'est un espèce de template pour
callback. Ce que le « extern "C" » rend impossible. Reste les
macros, si le cas se présente souvent.)

Je ne pense pas que ce que je viens de dire soit d'une clarté
absolue,


Mais si... C'est un problème on ne peut plus connu, du fait
qu'il y a tellement d'API définies en C.

[...]
Est-ce une manière courante de fonctionner? Sinon quelles
autres alternatives s'offrent à moi?


S'il n'y a pas de paramètre void*, il n'y a pas beaucoup
d'autres solutions. Mais il pose un problème dès qu'on veut
inscrire la même fonction plusieurs fois, mais sur des données
différentes.

Parfois, tu peux le contourner aussi avec un std::map et
d'autres informations. Si, par exemple, tu as un callback par
élément graphique, et que l'API te donne une indentificateur de
l'élément graphique, tu peux faire quelque chose du genre :

static std::map< GUIId, MaClasse* > objectMap ;

extern "C" void
callback( CUIId id )
{
objectMap[ id ]->f() ;
}

--
James Kanze
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34