Newsgroup: it.comp.lang.c++
Titolo: Passaggio di funzione membro

#include "iostream"
using namespace std;
typedef int Doppio (int,int);
void RiceviFunzione(Doppio x)
 {
 x(3,5);
 }
int DoppioEsterno(int x, int y)
 {
 cout << x+y << endl;
    return 0;
 }
class Oggetto
 {
 public:
  Oggetto(){cout << "Oggetto creato" << endl;}
  ~Oggetto(){cout << "Oggetto distrutto" << endl;}
 int DoppioInterno(int x, int y)
  {
  cout << x*y << endl;
     return 0;
  }
 void PassaFunzione(Doppio x)
  {
         RiceviFunzione(x);
  }
 };
int main(int argc, char* argv[])
{
Oggetto a;
a.PassaFunzione(DoppioEsterno);
// a.PassaFunzione(a.DoppioInterno); Come si può far funzionare questa?
return 0;
}

 questa?
	Attenzione: "DoppioInterno" non e' di tipo "Doppio". Ricorda che le
funzioni membro sono in realta' delle funzioni che hanno un primo
parametro nascosto consistente nell'indirizzo dell'oggetto.
	Una possibile soluzione e' rendere "static" la funzione DoppioInterno
(nel qual caso non c'e' piu' il parametro nascosto). Poi sostituisci la
riga di sopra con:
a.PassaFunzione(Oggetto::DoppioInterno);
	Se non vuoi che la funzione membro sia static, ci sono soluzioni piu'
complicate che possono coinvolgere template, binders e oggetti funzione.
Ciao
_dave_


Mi va bene rendere la funzione static, tuttavia non capisco la logica della
cosa. Se una classe ha una variabile membro di tipo int, una volta
instanziato l'oggetto potrň farci quello che voglio, compreso passare
qull'int a funzioni esterne che accettano int. Cosa che non avviene per le
funzioni membro mi pare di capire. In ogni caso, se ho capito, il primo
parametro della funzione membro č l'indirizzo, cioč, un puntatore ad un tipo
della classe a cui appartiene?

Non sapevo che in C++ si potessero passare parametri di tipo funzione :)
Nel libro di Lippman, ho trovato solo come usare i puntatori a funzione...
Ciao
--
Luigi
--
void f (OS x) {while (x.getbugs() > 0); destroy(earth);};
f (windows); // Meno male!

 ha scritto nel messaggio
news:ap5c9.45637$pX1.1...@news2.tin.it...

E comunque, correggo, non va bene dichiararla static poichč in tal caso
tutto quello che c'č dentro la funzione deve essere anche static. Altre
soluzioni?

 Altre soluzioni?
	Nel caso che hai proposto funzionerebbe perfettamente. Nell'esempio che
ho fatto io no, andrebbe resa static anche la x. E' questo che vuoi
dire? Non ti capisco.
	Se invece il tuo problema e' un altro (nel senso che non e' quello
dell'esempio), esponilo e cosi' possiamo discutere di qualche soluzione.
Cosi', in generale, ti consiglio di dare un'occhiata al capitolo §18.4
dello Stroustrup, che parla degli oggetti funzione. Ne parla nell'ambito
della libreria standard, ma spiega dei concetti che sono piu' generali e
che puoi utilizzare anche in altri ambiti.
_dave_

 dell'esempio), esponilo e cosi' possiamo discutere di qualche soluzione.
Presto detto (ed anche un po OT). Ho una classe (Form) che alla sua
creazione richiede l'indirizzo di una funzione di sistema di tipo WNDPROC
che risponde agli eventi (WM_COMMAND, WM_CHAR, etc). L'approccio "classico"
in questi casi (a quanto vedo in giro) è quello di creare una funzione
WNDPROC globale (che il c++ aborrisce?) e infilarla in qualche cpp sperduto.
Il sistema funziona bene (credo) e al momento, quando avviene l'evento, la
procedura globale attraverso un contorto sistema di puntatori rintraccia la
finestra (Classe) che lo ha generato è ne chiama la funzione corrispondente,
WM_COMMAND chiama Form->OnCommand(), WM_NOTIFY chiama Form->OnNotify(), etc.
Per inciso, chiama le funzioni dichiarate virtuali nella classe Form ed
implementate nelle classi discendenti (Form1->OnCommand() etc..).
Per tornare IT, il post nasce dalla curiosità di vedere se è possibile
rendere la funzione WNDPROC membro di una classe, ma dato che tale funzione
ha parametri e valori di ritorno imposti dal sistema, probabilmente non si
può (è oltretutto la funzione globale funziona ed è forse più efficiente del
crearne una per ogni classe).

 }
Non puoi trattare le funzioni memebro come normali funzioni, a meno che non 
siano statiche. I puntatori alle funzioni memebro devono essere sempre 
assopciati al tipo di oggetto, e quando invochi i memebri devi usare una 
istanza dell'oggetto. Ti accludo un esempio di uso di punt. a funzione per 
chiarezza ( la sintassi NON è semplicissima )
#include <iostream>
using namespace std;
class A {
    public:
            int z;
            void f( int a ){ z=a; }
};
void func( A &a,void (A::*p)(int) , int z ){
        (a.*p)(z);
}
int main( ){
        A       a;
        func( a,  &A::f, 4 );
        cout << "a.z = " << a.z << endl;
        return 0;
}

 probabilmente non si può
	Ah ah ah, bellissimo! Stesso identico problema che avevo avuto anche io
un po' di tempo fa. Volevo fare una classe finestra che registrasse la
sua WNDPROC (che doveva essere virtuale); pero' il tipo era diverso e
non potevo dichiararla static (oltretutto le funzioni virtuali non
possono essere static, ovviamente!). Percio' la classe wrapper la feci
lo stesso, ma il puntatore alla wndproc la passavo come parametro,
inevitabilmente.
_dave_


http://groups.google.it/groups?q=%2Bpuntatore%2Bfunzione%2Bmembro%2Bmusatti&hl=it&lr=&ie=UTF-8&selm=3BF4D3D5.61230F9%40divalsim.it&rnum=10
Questo (lungo) link potrebbe essere illuminante.
Una alternativa complicata e' usare il pattern "command".
Cesare

 Questo (lungo) link potrebbe essere illuminante.
Tratto dal link
[...]
int (A::* pfm )(int) = &A::f;
A * pa = new A;
int j = pa->*pmf(1);
[...]
Mi sembra ( ed il gcc me lo ha confermato ) che ( ) ha la precdenza su *, 
per cui diventa
int j = pa->*(pmf(1));
che ovviamente non ha senso
Quindi la sintassi giusta dovrebbe essere
int j = (pa->*pmf)(1);

 int j = (pa->*pmf)(1);
C'e' anche un altro errore: prima dichiaro "pfm" e poi uso "pmf" (questo
gcc non te l'ha segnalato? ;-). In effetti ai tempi probabilmente non
avevo compilato.
Ciao,
Nicola

 avevo compilato.
La cosa che mi ha lasciato perplesso è che molti esempi ( su internet, 
trovati con google ) riportano l'uso SENZA le parentesi....
Forse un tempo il gcc era + elastico... qualcuno sa come si comportano gli 
altri compilatori ( VC, BC etc etc etc  )

 altri compilatori ( VC, BC etc etc etc  )
Comeau pretende le parentesi.
Ciao,
Nicola

Salve ragazzi,
approfitto di questo thread per chiarirmi un dubbio.
supponiamo che :
1.le classi D1 e D2  siano derivate da B;
2.In B e' definita una funzione membro virtuale pura f1;
3.In B e' definita una funzione f2 che abbia come argomento un
puntatore ad una funzione  correlata ad f1; ad esempio la funzione f1
potrebbe essere una funzione di stampa, e f2 una funzione di scansione
di una lista di oggetti;
Nell'implementazione di D1 e D2 vorrei definire f1.  Riporto il codice
usato contrassegnando la riga dubbia:
#include <iostream>
using std::cout;
using std::endl;
class B
{
 public:
 int i;
 void set(int val)
 {
	i=val ;
 }
 void apply ( void (B::*fp)() ) // !!! come dichiarare fp ?
 {
   (this->*fp)() ;
 }
}  ;
class D1 : public B
{
  public:
  void print()
  {
   cout << "in D1 : " << i << endl ;
  }
} ;
class D2 : public B
{
  public:
  void print()
  {
   cout << "in D2 : " << i << endl ;
  }
} ;
main()
{
    D1* pD1=new D1();
    D2* pD2=new D2();
    pD1->set(100);
    pD2->set(200);
    pD1->apply(&D1::print) ; // B::apply vuole un 'void (B::*)()' !!!
    pD2->apply(&D2::print) ;
    delete pD1;
    delete pD2;
    return 0;
}
 
ciao
Luca

 }  ;
Ciao,
Nicola