Newsgroup: it.comp.lang.c++
Titolo: Passaggio di una funzionme ad un'altra funzione

Ciao a tutti i membri del gruppo.
Ho un problemino con il passaggio di una funzione membro definita
all'interno di una classe ad un'altra funzione membro della stessa
classe che deve utilizzarla.
Prima vi mostro il frammento originale dove viene dichiarata la
funzione
utilizzata poi nel MAIN program: cosě funziona.
int broyden(void (*f)(double *x,double *fv,int n),
	double *x0,double *f0,int n,double *eps,int *iter)
{  //........
   //.......
}
void f(double *x,double *fv,int n)
{
    fv[0] = cos(2.0*x[0]) - cos(2.0*x[1]) -0.4;
    fv[1] = 2.0*(x[1]-x[0]) + sin(2.0*x[1]) - sin(2.0*x[0]) - 1.2;
}
int main()
 {
    double *x,*r,eps;
    int n,ecode,iter;
    n = 2;
    x = new double[n];
    r = new double[n];
    x[0] = 0.1;
    x[1] = 0.5;
    eps = 1e-12;
    iter = 20;
    ecode = broyden(f,x,r,n,&eps,&iter);
    cout << "Iterations: " << iter << endl;
    cout << "x[0] = " << x[0] << endl;
    cout << "x[1] = " << x[1] << endl;
    delete [] x;
    delete [] r;
    return 0;
}
Io vorrei scrivere il codice nel seguente modo, ma quando lo lancio
ottengo un errore:
error C2664: 'broyden' : cannot convert parameter 1 from 'void (double
*,double *,int)' to 'void (__cdecl *)(double *,double *,int)'
// *****************
class BASE
{
public:
	int broyden(void (*f)(double *x,double *fv,int n),
	           double *x0,double *f0,int n,double *eps,int *iter)
	{  	//........
   		//.......
	}
};
class DERIVED : public BASE
 
{
public:
//....
//....
	void  f(double *x,double *fv,int n);
        void  radici(double *z);
};
void DERIVED::f(double *x,double *fv,int n)
{
	fv[0] = cos(2.0*x[0]) - cos(2.0*x[1]) -0.4;
	fv[1] = 2.0*(x[1]-x[0]) + sin(2.0*x[1]) - sin(2.0*x[0]) - 1.2;
}
void DERIVED::radici(double *z)
{
    double *x,*r,eps;
    int n,ecode,iter;
    n = 2;
    z = new double[n];
    r = new double[n];
    z[0] = 0.1;
    z[1] = 0.5;
    eps = 1e-12;
    iter = 20;
// come si vede voglio passare f a broyden
// ma secondo me come la passo io č sbagliato, voi che dite ?
    ecode = broyden(f,z,r,n,&eps,&iter);
    cout << "Iterations: " << iter << endl;
    cout << "z[0] = " << z[0] << endl;
    cout << "z[1] = " << z[1] << endl;
    delete [] r;
}
//  **** MAIN ****
#include <iostream.h>
#include <math.h>
int main()
{
    DERIVED      der;
	int n;
	n = 2;
    	double *T;
	T = new double[n];
	T[0] = 0.5;
	T[1] = 1;
	der.radici(T);
    ofstream out("mathematic.out", ios::trunc, 0);            // per
la stampa dei risultati.
    if(!out) nrerror("impossibile aprire il file");
	out << " radici : T1 = " << T[1] << ", T2 = " << T[0]
		<< endl;
	delete T;
	return 0;
}
Spero che qualcuno possa aiutarmi.
Intanto ringranzio tutti i membri che hanno letto il mio post.
Grazie, Davide.

 	           double *x0,double *f0,int n,double *eps,int *iter)
prova cosě:
  	int broyden(void (*BASE::f)(double *x,double *fv,int n),
Perň si puň fare meglio...
Un cosiglio: dai uno sguardo a "Design Pattern" di E. Gamma... ti si 
apriranno gli occhi!
Ciao

 double *x0,double *f0,int n,double *eps,int *iter)
[cut]
lo sai che mi hai fatto sbroccare subito all'inizio del programma :-p
non capisco perche' se devi definire un puntatore a funzione dichiari i dati
pure dentro ad essa ... mi hai fatto andare un po' insieme la vista.
cioe' molto piu' comprensibile per me' e' questa forma:
 int broyden(void(*f)(double*,double*,int) , double *x0,double *f0,int
n,double *eps,int *iter)
non ti pare ? almeno uno che nota una dichiarazione senza nomi annusa subito
il puntatore a funzione, io la ho riletta 2-3 volte per notarlo, alle prime
passate mi pareva un'altra cosa.
ah altro punto passare strutture o oggetti al posto di tutta quella sfilza
di variabili ?
ciao

   int broyden(void (*BASE::f)(double *x,double *fv,int n),
In primo luogo, non basta cambiare la signature, bisogna anche cambiare
l'implementazione e, soprattutto, fare in modo che broyden() riceva in qualche
modo un oggetto BASE su cui invocare la funzione. (La sintassi è inesatta,
comunque: bisogna scrivere "BASE::*f").
In secondo luogo, c'è comunque un problema. Se broyden() vuole un puntatore a
funzione membro non-statica di BASE, non sarà possibile passargli un puntatore
a funzione membro di DERIVED. (Il contrario è invece possibile.)
Nel esempio in questione, comunque, non c'è alcuna ragione visibile perché f()
sia un membro non-statico. Se l'OP vuole compilare quel codice, dovrebbe
essere sufficiente dichiarare static la funzione DERIVED::f().
Max

Intanto grazie a tutti.
provo a fare le modifiche che mi avete consigliato e poi vi faccio sapere.
Grazie, Davide.

 a funzione membro di DERIVED. (Il contrario è invece possibile.)
Per questo dicevo di leggersi il Gamma. Credo che comunque una cosa del 
genere in generale vada evitata, meglio fare una classe "funzione"...
Luigi

OK ragazzi grazie mille, definendo la funzione f(....) come static
riesco a passarla a int broyden(......)
Tuttavia la funzione f che devo costruire è ben più complicata perchè
le componenti di *fv :
fv[0] e fv[1] sono costruite tramite funzioni definite in una seconda
classe base.
Mi rendo conto che vi sto rubando del tempo ragazzi, ma per me è molto
importante risolvere questo problema.
Il programma non è facile, ma è sicuramente una bella sfida.
Non vi chiedo di rispondere subito, ma se poteste aiutarmi ve ne sarei
molto grato.
E' da 3 mesi che programmo e  sto studiando molto questo linguaggio,
ma a volte sorgono dei problemi più grandi e nuovi.
Grazie a tutti.
Notate che comunque se  definissi f come nei post precedenti il
programma gira!
Ma lasciate che vi spieghi cosa deve fare il mio programma:
A) Per prima cosa voglio costruire una classe BASE_1   che funga da
libreria matematica, in cui viene definito il metodo
     numerico broyden per la soluzione di equaz. non lineari:
//***********************************************
class BASE_1 {
public:
    int broyden(void (*f)(double *x,double *fv,int n),
            double *x0,double *f0,int n,double *eps,int *iter);
};
int BASE_1::broyden(void (*f)(double *x,double *fv,int n),    
                         double *x0,double *f0,int n,double *eps,int
*iter)
{
    // .
    // .
    // .
    // .  
}
//*******************************************************
B) Dopodichè definisco una classe BASE_2   (template di una classe
MODEL) in cui definisco alcune funzioni necessariemente
    appartenenti a BASE_2, che sfrutterò poi nella classe derivata
SISTEMA.
//*************************************************
template <class MODEL> class BASE_2 
{
public:
             //.
             //.
             //.
	float DeltaH(*P);
             //.
             //.
};
template <class MODEL>  float BASE_2<MODEL>:: DeltaH(*P)
{
         //.
         //.
}
//***************************************************
C) Infine ecco la classe SISTEMA che deriva entrambe le classi sopra
descritte:
//******************************************************************
template <class MODEL> class SISTEMA : public BASE_1, public 
BASE_2<MODEL>
{
public:
	float *m;
	float *k;
 
	SISTEMA(MODEL X);
	~SISTEMA();
	SISTEMA(const SISTEMA<MODEL> &obj);
	static  void   f(double *x,double *fv,int n);
              void             radici(double *z);
};
// Costruttore
//°°°°°°°°°°°°°°°°°°°°°
template <class MODEL> SISTEMA<MODEL> ::SISTEMA(MODEL  X):  
BASE_2<MODEL> (X)
{
	m = new float;
	k =new float;
              P = new float;
 
	*m= 5.0;
	*k= 3.0;
              *P = 3.2;
}
// Costruttore di copia
//°°°°°°°°°°°°°°°°°°°°°
template <class MODEL> SISTEMA<MODEL> ::SISTEMA(const SISTEMA<MODEL>
&obj)
{	
	m = new float;
	k =new float;
              P = new float;
 
	*m=*obj.m;
	*k= *obj.k;
	*P= *obj.P;
}
// Distruttore
//°°°°°°°°°°°°°°°°°°°°°
template <class MODEL> SISTEMA<MODEL> ::	~SISTEMA()
{
	delete m;
	delete k;
	delete P;
}
template <class MODEL> void SISTEMA<MODEL> ::   f(double *x,double
*fv,int n)
{
	fv[0] = DeltaH(*P) * (*m) * pow(x[0],2);
	fv[1] = DeltaH(*P) * (*k) * Log(x[1]);
}
// L'errore che ottengo nel compilare è che non riconosce i puntatori
e dice
//  error C2352: 'POINT<class WATER>::DeltaH_PT' : illegal call of
non-static member function
// A parte errori di sintassi in altre parti del programma credo che
il compilatore voglia che le variadili utilizzate da f,
// che è stata dichiarata static, siano tutte statiche, ma per me
sarebbe un problema visto che le funzioni di BASE_2
// potrebbero essere utilizzate contemporaneamente  anche in altre
classi derivate diversa da quella in esame .
template <class WorkingFluid> void
SISTEMA<WorkingFluid>::radici(double *z)
{
    double *r,eps;
    int n,ecode,iter;
    n = 2;
    r = new double[n];
    eps = 1e-06;
    iter = 20;
    ecode =  broyden(f,x,r,n,&eps,&iter);
    cout << "Iterations: " << iter << endl;
    cout << "z[0] = " << z[0] << endl;
    cout << "z[1] = " << z[1] << endl;
    delete [] r;
}
//****************************************************************
ed ecco il MAIN
//°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
int main()
{
    MODEL                               mod;
    SISTEMA<MODEL>	System(mod);
	int n;
	n = 2;
              double *T;
	T = new double[n];
              T[0] = 400.00;   // T3
              T[1] = 300.00;   // T1  
	System.radici(T);
    ofstream out("mathematic.out", ios::trunc, 0);            // per
la stampa dei risultati.
    if(!out) nrerror("impossibile aprire il file");
	out << " radici : T1 = " << T[1] << ", T3 = " << T[0]
		<< endl;
	delete T;
	return 0;
    return 0;
}
Grazie per aver letto tutto sto fardello.
Spero di essere stato chiaro nell'esporre il problema.
Ciao Davide.