Newsgroup: it.comp.lang.c++
Titolo: [?] Indirizzo di funzioni membro

Salve raga avrei bisogno di un aiutone:
ho una classe che serve da base per una definita dall'utente.
avrei bisogno di avere un puntatore che punti a funzioni che definisce
l'utente nella classe che deriva, in modo da poterle chiamare dalla mia
classe base.
Ora: non posso prevedere che classe creerà l'utente e tra l'altro non mi
sembra che sia un ottima idea parametrizzare la mia classe dato che dopo ce
ne sarà un altra (l'ultima)  che deve avere dei collegamenti a questa mia
classe per richiamare una funzione (che sta volta so), e dalle prove che ho
fatto, sembra che questo crei molti problemi.
La soluzione delle funzioni Virtual  è quella che sto usando al momento, ma
non vorrei costringere l'utente ad usare nomi dati da me, o limitarlo nel
numero di funzioni inseribili....
in sostanza ditemi come faccio a fare un puntatore a una funzione membro di
una classe (senza dichiararla staic, dopo deve agire su dei parametri
privati...) ammesso che di questa so solo che deve essere
void Nome();
ah, non so neanche come prenderne l'indirizzo, e poi come richiamarla....
HELP!!!
almeno ditemi se si può fare o è meglio cambiare idea...
'bye

numero di funzioni inseribili....
[omissis]
Non sono sicurissimo di aver capito bene tutto, comunque qualcosina
credo di averla azzeccata...
Premetto che se fossi al tuo posto penserei bene su quel che starei cercando di fare,
ma assumo che questo tu l'abbia gia` fatto e sia sicuro della tua scelta.
Innanzitutto la soluzione con puntatori membro non puo` funzionare (o quasi...).
Ti faccio un esempio:
class Base {
  public:
    typedef void (Base::*Func)();              // osservare l'esplicito riferimento a Base
    void Foo(Func F) {
      (this->*F)();
    }
    void Pippo(){ return; };
  private:
    /* ... */
};
class Derived : public Base {
  public:
    void g() { return; };
};
int main() {
  Base a;
  a.Foo(&Base::Pippo);
  // Derived b;
  // a.Foo(&Derived::g);
  return 0;
}
Come vedi nella "dichiarazione di tipo" (non e` il termine giusto, ma non
trovo niente di piu` adatto) di puntatore a funzione membro (la typedef) bisogna
fare esplicito riferimento al nome di una classe.
Se compili questo codice cosi` com'e` non ci dovrebbero essere errori, ma
se provi a decommentare le due righe della main ti accorgi che la soluzione va
a rotoli. Il fatto e` che la nuova funzione membro introdotta in Derived non e` un
membro di Base.
Questa soluzione dunque sembra non abbia speranze...
In effetti c'e` ancora una cartuccia da sparare... i template che ogni tanto
ci tirano fuori dai guai.
Se proprio non vuoi usare le funzioni virtuali per non imporre nomi, puoi
ricorrere all'uso di una classe proxy che serve a passare a Base l'indirizzo
della funzione membro e ovviamente anche l'indirizzo dell'oggetto su
cui richiamare la funzione membro. L'uso della classe proxy non e` necessario
e potrebbe essere evitato, ma sembra che la keyword template non
vada d'accordo con la typedef ( e penso di capire il perche`), l'artificio e`
dunque necessario.
Ecco il codice di esempio:
#include <iostream>
using namespace std;
template<class T>
struct Proxy {
 void (T::* Func)();
 T* ThisPtr;
};
class Derived;       // artificio
class Base {
  public:
    /* template <class T> */                                 // dritta!
    void Foo(Proxy<Derived> F);                       // template istanziato x limitazioni compilatore
};
class Derived : public Base {
  public:
    void g() { cout << "ciao mondo!" << endl; };
};
void Base::Foo(Proxy<Derived> F) {
  ((F.ThisPtr)->*(F.Func))();
}
int main() {
  Base a;
  Derived b;
  Proxy<Derived> P;
  P.ThisPtr = &b;
  P.Func = &Derived::g;
  a.Foo(P);
  char c;
  cin >> c;
  return 0;
}
Innanzi tutto, mi scuso per la soluzione poco OO, ma
1) L'ho scritta di getto in 10 minuti
2) Il mio compilatore non supporta i template member e` ho dovuto
    far uso di qualche artificio (tipo istanziare esplicitamente il template),
    ma ho messo una dritta per capire dove mettere il template.
Per esercizio (permettimelo) ti lascio:
a) Capire come funziona
b) Portare il template dentro Base
c) Cercare di sistemare il tutto in ottica piu` OO
d) Valutarne la convenienza rispetto all'uso di funzioni virtual tenendo conto che
     siamo ai limiti del lecito (in effetti stiamo giocando anche col type system)... per
     non dire che stiamo cominciando a giocare sporco!
Ovviamente questo approccio ha dei limiti, ad esempio funziona anche con classi
non derivate da Base!
Ora dopo questo breve momento di gloria, spero di non ruzzolarmi e sprofondare nel
piu` profondo dei baratri!
Saluti,
Paolo
P.s.
   Se qualche anima volenterosa risolvesse almeno l'esercizio B e disponesse
   di un compilatore migliore del mio, mi piacerebbe sapere se la soluzione generale
   funziona veramente (come penso) oppure il mio compilatore sta cercando di
   illudermi (nel qual caso non mi resterebbe che ruzzolare e sprofondare nel baratro!).
   Grazie.
------------------------------------------------------------------
  Paolo Marotta
  Computer Science, University of Pisa
  home:   
http://www.cli.di.unipi.it/~marotta
------------------------------------------------------------------

Grazie mille, sei un dio, ho già attaccato il tuo posterone in camera!
Cmq, non è vero ciò che dicevi, ovvero che non era possibile farlo
funzionare nel primo modo (quello senza i template) mastava fare un megamaxi
iper recatsing!!!!
allora, io adesso SONO riuscito a far chiamare dalla classe base, una
funzione definita e iscritta dall'utente nella sua personalissima classe
derivata.
adesso conto di sovraccaricare un operatore (si può con i template?) per
iscrivere la funzione alla lista, così risulta tutto molto più figo.
Cmq  copio-incollo qua le parti più interessati del codice, non ce lo metto
tutto per fare prima, quello che non c'`e è facile da immaginare e direi
anche un po inutile
class Base{
    typedef void(Base::*PMemberFunction)();
    public:
              Base();
             ~Base();
        void GetHandle(PMemberFunction);
        void CallHandle();
        PMemberFunction Handle;
};
class Derived:public Base{
        int Value;
    public:
              Derived();
             ~Derived();
        void View();
        void Get(int);
};
// costruttori  e distruttori banali di Base omessi per ovvi motivi
void Base::GetHandle(PMemberFunction Req){
        Handle = Req;
}
void Base::CallHandle(){
        (this->*Handle)();
}
Derived::Derived(){
        GetHandle ((PMemberFunction)(&Derived::View));  // LA PARTE
INCRIMINATA !!!!!!
}
Derived::~Derived(){}
void Derived::View(){
         cout << "\nSono il View di derived";
}
Derived::Derived(){
        GetHandle ((PMemberFunction)(&Derived::View));
}
//// ora il main
void main () {
Derived MyP;
        MyP.Get(5);
        MyP.CallHandle();
}
qiesto stampa 5 come volevasi dimostrare :)
quello che fa la View è un semplice cout di Value
e la Get mette il valore che dico io in Value, questo per essere sicuro che
agisca sui dati membro di quella classe
WOW!!!!!
ora il prossimo passo è implementare un operatore, mi sa che sarebbe meglio
binario del tipo
Derived + View,
credete che si possa fare?
mah, cmq va già alla grande cosi, se  poi si pùo fare di più, meglio, molto
meglio.
il fatto è che ora questo operatore devevalere per la classe derived, ma
anche per la classe derived2 etc etc...
ovvero lo vorrei fare coi template... mah, se ci riesco posto la soluzione,
se avete idee MANDATE MANDATE che vi faccio il posterone anche a voi
'bye!!!

se avete idee MANDATE MANDATE che vi faccio il posterone anche a voi
Spiegati meglio, magari con un esempio di cio` che vorresti fare...
Saluti,
Paolo


Grazie del tuo aiuto, ho risolto tutto e anche di più, il fatto è che ti
sfugge qualcosa proprio perche non te l'ho detta :)
Cmq non appena avrò tutto pronto ti mando un esempione e allora...WOW!!!
Lo so che non è chiaro un bel niente di quello che voglio fare, cmq hai
risolto il mio problema
Il problema dei template l'ho risolto in un modo un pochino diverso e che
non centra ninete, ho semplicemente definito una macro, che mi piace anche
di più e secondo me è più versatile..... sempre per quello che voglio fare
io
caso mai ti mando qualcosa per posta