Newsgroup: it.comp.lang.c++
Titolo: [help] si può passare l'indirizzo di un membro?

stavo cercando di fare una classe per semplificarmi un po' le cose.
dovrei assegnare a un elem. di una struttura l'indirizzo della funzione
perň gli voglio passare l'indirizzo del membro della mia classe
non so se č possibile, se c'č un modo
ecco il pezzo di codice incriminato
bool BaseClass::Register(string strClassName)
{
 WNDCLASSEX wcex;
 wcex.lpfnWndProc = BaseClass::WndProc;   //   <---- il casting impossibile
(?)
e ecco come VC++6 si irrita:
custom.cpp(10) : error C2440: '=' : cannot convert from 'long (__stdcall
BaseClass::*)(struct HWND__ *,unsigned int,unsigned int,long)' to 'long
(__stdcall *)(struct HWND__ *,unsigned int,unsigned int,long)'
        There is no context in which this conversion is possible
main.cpp
Error executing cl.exe.
č possibile oppure mi devo rassegnare?
non c'č proprio nessun modo/alternativa/workaround?
grazie in anticipo
--
ciao
..::[xaero]::..

(?)
Ammesso che BaseClass::WndProc sia di tipo 
LRESULT CALLBACK WindowProc(
    HWND hwnd,	// handle of window
    UINT uMsg,	// message identifier
    WPARAM wParam,	// first message parameter
    LPARAM lParam 	// second message parameter
   );	
 
l'unico modo che conosco per fare un simile assegnamento e quello di
rendere 'static'  BaseClass::WndProc .
ciao

(?)
Questo e' un problema abbastanza comune che incontra chi si avvicina
al C++ (in particolare se proviene dal C). Un puntatore ad una
funzione membro non statica non e' la stessa cosa di un puntatore
a funzione: per essere utilizzato ha bisogno di sapere su quale
istanza deve lavorare...
  #include <iostream>
  class MyClass
  {
    public:
      void m1(int x)
      { std::cout << "MyClass::m1(" << x << ")\n"; }
 
      void m2(int x)
      { std::cout << "MyClass::m2(" << x << ")\n"; }
 
      void m3(int x)
      { std::cout << "MyClass::m3(" << x << ")\n"; }
  };
  int main()
  {
    // Dichiara un array di tre puntatori a metodi di Myclass
    // che accettano un parametro intero e tornano void
    void (MyClass::*m[3])(int);
    // Inizializza i puntatori ai metodi
    m[0]=MyClass::m1;
    m[1]=MyClass::m2;
    m[2]=MyClass::m3;
    // Crea una istanza dell'oggetto: i metodi non statici
    // possono essere chiamati solo su istanze
    MyClass o;
    // Chiama i metodi di MyClass indirettamente (attraverso
    // i puntatori dell'array m). La differenza rispetto ai
    // puntatori a funzione e' che deve essere sempre presente
    // una istanza per poter chiamare un metodo non statico
    for (int i=0; i<3; i++)
      (o.*m[i])(i*3+2); // chiama l'i-esimo metodo su o
    return 0;
  }
I puntatori alle funzioni membro statiche sono invece dei
normali puntatori a funzione dal nome buffo (con "::"):
infatti in questo caso la funzione puo' essere chiamata
direttamente senza bisogno di una istanza.
Se l'istanza che devi chiamare e' statica (ovvero il compilatore
puo' considerare il suo indirizzo una constant expression)
allora si puo' ricorre a quelche trucchetto con template per
poter fare quello che chiedi...
   ...
   template<MyClass *p,void (MyClass::*m)(int)>
   void call_m(int x)
   { p->m(x); }
   MyClass o; // Istanza statica
   int main()
   {
     // Normale puntatore a funzione
     void (*f)(int);
     // Fa in modo che f chiami un metodo di o
     f=call_m<&o,MyClass::m1>;
 
     // Chiamata
     f(6502);
     return 0;
   }
/////////// INIZIO SEMI-OFFTOPIC ////////////
Per risolvere il problema che stai affrontando normalmente
si fa in modo che Windows si porti a spasso assieme ai dati
della finestra (associati all'HWND) anche il puntatore alla
istanza della classe C++ in un puntatore allocato nei
window extra bytes. Per fare questo quando registri la
classe imposti cbWndExtra a 4 e poi usi qualcosa come:
  // Metodo STATICO di BaseWindow (che puoi mettere come
  // WindowProcedure nella window class)
  LRESULT CALLBACK BaseWindow::StaticWndProc(
    HWND hwnd,
    UINT msg,
    WPARAM wparam,
    LPARAM lparam)
  {
    // Alla creazione della finestra associo l'istanza
    if (msg==WM_CREATE)
    {
      // Recupera l'indirizzo dell'istanza che e'
      // stato passato da CreateWindow e lo memorizza
      // assieme alla finestra
      SetWindowLong(hwnd,0,
        (long)((LPCREATESTRUCT)lparam)->lpCreateParams);
    }
    // Recupera l'istanza associata
    BaseWindow *p=(BaseWindow *)GetWindowLong(hwnd,0);
    // Chiama il metodo di gestione (non statico)
    return p->WndProc(hwnd,msg,wparam,lparam);
  }
L'indirizzo dell'istanza lo devi passare nella chiamata
a CreateWindow.
HTH
Andrea
--
Andrea Griffini, Programmer
http://www.netservers.com/~agriff