Newsgroup: it.comp.lang.c++
Titolo: Linguaggi di programmazione?

Ciao a tutti.
Voglio tuffarmi nel mondo della programmazione.
Secondo Voi da dove devo cominciare?
Posso, ad esempio, cominciare a studiare il linguaggio
C++ senza conoscere il C?
Datemi qualche consiglio!
Che linguaggio di programmazione č piu' utilizzato
al giorno d'oggi?
Vi ringrazio molto.
Alex

al giorno d'oggi?
Il COBOL
;)
--
Andrea Laforgia - walkietalkie(at)
libero.it
http://www.geocities.com/AndreaLaforgia

Secondo Voi da dove devo cominciare?
il Python 
www.python.org
--
Rhymes - 
rhy...@myself.com
http://www.foxhound-games.it
"Sapete cosa fa un InputStream quando
gli si racconta una barzelletta? Reader..."

al giorno d'oggi?
Sono molto utilizzati VB, C, C++, Pascal e Java ma non è detto che il
loro utilizzo si proporzionale alla loro "bontà".
-- 
Marco Barisione (ICQ 84277092)


Io ti consiglio di iniziare con il C++ direttamente... Compra un buon libro
per principiante (ad esempio il Lippman).
Ti sconsiglio caldamente di iniziare con il C, poichè così facendo
acquisterai un sacco di brutte abitudini che poi saranno dure a morire...
Infine evita linguaggi tipo Pascal o cmq non orientati agli oggetti, poichè
dopo dovrai fare un sacco di lavoro per "convertitrti" ad un linguaggio
basato sugli oggetti.
Ah un'ultima cosa... nel caso in cui tu voglia iniziare con il C++, evita di
comprare il libro dello Stroustrup (il creatore del linguaggio) perchè è per
gente che già sa qualcosa, sia di C++ che di programmazione in genere;
potrai cmq acquistarlo in seguito per affinare le tue tecniche

basato sugli oggetti.
Non condivido.
Programmare in C++ non vuol dire necessariamente progettarsi
classi.  Acquisire il modello procedurale puo' essere molto
molto utile e il Pascal aiuta in questo.


per principiante (ad esempio il Lippman).
Iniziare dal C++? IMO è troppo difficile, è meglio iniziare da un
linguaggio semplice come Python. Non penso che sia giusto che un
principiante debba scontrarsi con l'uso dei puntatori o altre simili
"amenità".


 molto utile e il Pascal aiuta in questo.
Concordo con Andrea. Ho la sensazione che la nuova generazione di
programmatori, nati e cresciuti con Java, veda il mondo come derivato da
un'unica classe e talvolta e' piuttosto difficile far capire loro che
esistono alternative come l'eredita' multipla o... addirittura...
nessuna eredita' :-)
Credo che il passaggio dal paradigma a oggetti a quello procedurale sia
almeno altrettanto difficile da quello inverso.
Cio' non toglie che se l'obbiettivo e' imparare il C++, conviene
iniziare direttamente da quello.
Ciao,
Nicola

se vuoi iniziare dal c++ ti consiglio il libro "C++ Fondamenti di
programmazione" di Deitel e Deitel

 wrote in message
3ba7c0b...@News.CIS.DFN.DE...

Amenità? Io non credo proprio che lo siano... come implementi liste e alberi
altrimenti? Non credo che nascondere le cose al programmatore aiuti...


Un attimo, io non ho detto che il paradigma ad oggetti sia l'unica strada,
ho detto solo che il passaggio da uno stile procedurale ad uno ad oggetti è
difficile. Però credo (e forse qui potrei sbagliarmi) che per progettare
programmi di una certa complessità, la capacità di poter definire tipi di
dati astratti sia fondamentale; e dato che oggi è fondamentale esser
aggiornati, tanto vale iniziare direttamente a pensare in questi termini.
Tutto qui.
Ah un'ultima cosa: non sono nato e cresiuto con il Java, ma con il Basic e
il C, per poi imparare l'odiato Pascal a forza a scuola.
Il passaggio alla programmazione ad oggetti mi è rimasto molto difficile,
percui il consiglio che ho dato era basato sulla mia personale esperienza,
che poi può non essere stata la stessa per un altro.

 aiuti...
python mi risulta abbia le liste nella forma 
lista = ['questa', 'lista', 100, 1234]
puoi implementare gli alberi con le liste, e quale sarebbe il lato 
oscuro della cosa?
a questo punto non sarebbe giusto nemmeno nascondere la vtable del 
polimorfismo, o il linking dei template...

difficile. 
Il C++ e' un linguaggio che implementa piu' paradigmi.
Non e' strettamente necessario usare un paradigma ad
oggetti.  


 che poi può non essere stata la stessa per un altro.
Sono sicuro che per molte persone e' cosi' e non trovo sbagliato in se'
il tuo consiglio. Solo e' importante sapere che ci sono altre cose
intorno, in modo da non arrivare completamente impreparati al prossimo
"salto" di paradigma.
Ciao,
Nicola

"salto" di paradigma.
E quale potrebbe essere il prossimo paradigma aggiunto al C++ (o a un
suo discendente)? Esistono linguaggi (magari quasi sconosciuti e poco
diffusi) che utilizzano un nuovo paradigma che potrebbe diffondersi e
diventare importante come ad esempio quello ad oggetti?




Esistono paradigmi, peraltro tutt'altro che nuovi, che il C++ non
supporta nativamente, ma che magari sono implementati con maggiore o
minore successo in alcune librerie. Mi vengono in mente la
programmazione funzionale e la programmazione generica basata su
tipizzazione dinamica (ad es. Python).
Pero' prova a spiegare ad un programmatore Java l'utilita' dei template
o dell'ereditarieta' multipla...
Ciao,
Nicola

 molto utile e il Pascal aiuta in questo.
concordo in toto, e consiglio anche io il Pascal.
Non credo che basti qualche mese (o forse anno) di Pascal per acquisire una 
dimestichezza tale con la programmazione procedurale da non riuscire a 
cambiare paradigma. Almeno personalmente, io non ho avuto problemi a 
pensare ad oggetti (il discorso sarebbe diverso se il programmatore arriva 
da 20 anni di programmazione procedurale...)
ciao Anto
-- 
Antonio Cuni, 19 anni, studente
Brainbench C++ Master: 4.6, higher than 98% of all previous test takers.
C Language: 3.32, higher than 79% of all previous test takers.
Guida C/C++ di Programmazione.it: 
http://cpp.programmazione.it

 wrote in message
news:3ba9a9cb...@News.CIS.DFN.DE...

Di linguaggi che usano o permettono paradigmi diversi da quelli supportati (piu'
o meno bene) dal C++ ce ne sono moltissimi e da moltissimo tempo. Che poi questi
paradigmi possano o meno avere successo dipende. Io penso che sono migliori del
C++ (o dell'OO in generale) in alcuni contesti. Pensa al paradigma funzionale,
per esempio.
Comunque Python e Smalltalk (e altri) permettono la programmazione generica
tramite tipizzazione dinamica.
Lisp e tanti altri sono linguaggi basati sul paradigma funzionale.
In C++ puoi sempre scriverti un motore inferenziale e poi chiamarlo direttamente
costruendo le asserzioni con una qualche sintassi specificata da te, ma non
ottieni certo un environment paragonabile a quello del Prolog.
Il programming by contract non e' forse un vero e proprio paradigma, ma puoi
sempre dare un'occhiata a Eiffel e imparare un nuovo modo di pensare.
--
Andrea Ferro
---------
Brainbench C++ Master. Scored higher than 97% of previous takers
Scores: Overall 4.46, Conceptual 5.0, Problem-Solving 5.0
More info 
http://www.brainbench.com/transcript.jsp?pid=2522556

 comprare il libro dello Stroustrup (il creatore del linguaggio) perchč č
per
Anche su questo.
Ma il C++ e` *molto* pesante come primo linguaggio di programmazione.
E`, dopo tutto, il linguaggio piu` complicato fra i piu` diffusi.
Un 2-3 mesi passati a imparare "la programmazione in quanto tale"
(magari con un linguaggio assieme facile e potente come Python, v.
ad esempio il testo di Gauld, edito da Addison-Wesley) sono un
buon investimento prima di tuffarsi nel Lippman-Lajoie, secondo me.
Alex (MVP Brainbench per C++)

 o dell'ereditarieta' multipla...
ne approffito per avviare un subthread: ma e' davvero indispensabile 
l'ereditarieta' multipla? Premetto che io ne sono convinto, dato che mi e' 
capitato almeno un progetto (che purtroppo stavo scrivendo in Turbo Pascal 
with objects) in cui l'ereditarieta' multipla mi avrebbe permesso una 
soluzione semplice ed elegante. In ogni caso leggo spesso in giro che se ne 
puo' fare a meno, che e' inutilmente complessa, ecc. Cosa ne pensate?


 puo' fare a meno, che e' inutilmente complessa, ecc. Cosa ne pensate?
Giusto per fare un esempio, trovo molto comodo attribuire ad una classe
ruoli diversi a seconda del contesto; l'ereditarieta' multipla e' uno
strumento pratico per ottenere questo. Un approccio del genere ti
permette di realizzare classi che svolgono un ruolo di mediazione in
modo che ciascuna classe che interagisce con tale mediatore conosca solo
l'interfaccia che le compete.
Ciao,
Nicola

 puo' fare a meno, che e' inutilmente complessa, ecc. Cosa ne pensate?
La mia modesta opinione:
In se e per se non e' necessaria, se ci sono a disposizione altri mezzi. In
linguaggi a tipizzazione dinamica (per esempio Smalltalk) non e' mai necessaria
e puo' essere utile solo in pochissimi rarissimi casi (ed e' anche opinabile cha
una soluzione con MI sia migliore di una soluzione SI con eventuale contenimento
e/o delegazione). Infatti in Smalltalk non esiste.
In linguaggi a tipizzazione statica come il C++ invece e' quasi obbligatoria per
affrontare un certo tipo di design basato sulla definizione di interfacce
pubbliche. Da questo punto di vista trovo abbastanza valido l'approccio di Java
in cui l'ereditarietą dei tipi e' singola e quella delle interfacce multipla.
IMO l'ideale sarebbe separare completamente le interfacce (multipla e pubblica o
a tipizzazione dinamica) e le implementazioni (singola e privata, ma con
implementazione di interfacce multiple).


 implementazione di interfacce multiple).
concordo.
non credo che l'ereditarietà multipla per i tipi di dati sia indispensabile.
se il linguaggio separasse il concetto di interfaccia da quello di tipo di
dato, il programmatore dovrebbe necessariamente essere a conoscenza della
differenza tra le due cose, e così molti scriverebbero codice 'ben disegnato'.
:)
ciao :: xaero

non credo che l'ereditarietà multipla per i tipi di dati sia indispensabile.
Io creo che nel caso si utilizzi COM (sotto Win32), con il
sistema di interfacce che si ritrova, l'ereditarieta'
multipla sia indispensabile.


 multipla sia indispensabile.
ho chiaramente detto che non sarebbe indispensabile per i _tipi_di_dati_ nel
caso esistesse la distinzione tra interfaccia e tipo di dato, quindi intendevo
dire che quella indispensabile sarebbe solo l'ereditarietą multipla per le
interfacce.
ciao :: xaero

 multipla sia indispensabile.
Credo che xaero con il termine "tipi di dati" si riferisse ad una presupposta
gerarchia implementativa. E' il vecchio discorso di separazione fra gerarchia
dei tipi astratti e gerarchia dei tipi concreti. Assumendo tale separazione
nella gerarchia dei tipi concreti la MI e' totalmente inutile. In quella dei
tipi astratti puo' essere o meno utile a seconda della presenza o meno di
tipizzazione dinamica.
Credo fosse questo il discorso.


 tipizzazione dinamica.
Questo discorso non mi convince pienamente. Se e' vero che e' possibile
utilizzare contenimento e delega per implementare una gerarchia multipla
di interfacce, ma singola nell'implementazione, questo di solito avviene
a spese della compattezza del codice compensando la vera o presunta
scarsa manutenibilita' dell'eredita' multipla di implementazione.
Resta che questo tipo di schema va utilizzato con cautela, perche'
introduce dei forti elementi di rigidita' nel disegno che portano
effettivamente a difficolta' di reingegnerizzazione.
Ciao,
Nicola

 wrote in message
news:3BAB1BDD...@divalsim.it...

Non ho mica capito! Prendiamo Java. Java ha ereditarietà multipla nelle
interfacce e singola nell'implementazione. Con una sola differenza: una classe
concreta introduce sempre anche una "interfaccia". In altre parole quando
definisci una classe la definisci pubblicamente e ci puoi accedere anche tramite
metodi che questa definisce ma che non fanno parte delle interfacce da cui
deriva. Contenimento e delega non c'entrano. Le interfacce funzionano come
previsto con ereditarietà multipla. Non serve in genere ne contenimento ne
delega. La classe puoi considerarla in questo modo: introduce una nuova
interfaccia e deriva multiplamente da questa, da tutte quelle della classe base
e da tutte le interfacce che specifica. INOLTRE implementa tutte le interfacce
che non sono già implementate. Nota che e' possibilissimo ipotizzare un
linguaggio in cui queste due cose sono separate.


 di interfacce multiple).
non sono molto d'accordo. Dato per scontato che uno degli obiettivi sia 
quello del riuso del codice (magari anche solo all'interno dello stesso 
progetto) non condivido l'approccio di Java di fornire l'ereditarieta' 
multipla solo per le interfaccie.
Nei linguaggi a tipizzazione statica la MI *almeno* delle interfaccie mi 
pare indispensabile, e sino a qui ci siamo; pero' io mi riferivo 
soprattutto all'ereditarieta' dell'implementazione. Come ha gia' osservato 
Nicola, il riuso dell'implementazione attraverso, ad esempio, il 
contenimento obbliga a scrivere un sacco di metodi wrapper perdendo in 
compattezza e manutenibilita'; pensa, ad esempio, se aggiungi un metedo 
all'interfaccia pubblica di una delle classi riutilizzate per contenimento: 
occorre, ovviamente, tornare a modificare il codice "riusante" per scrivere 
nuovi wrapper.
Ai tempi in cui avevo affrontato per la prima volta il problema (in cui, 
ripeto, usavo il turbo pascal) avevo risolto proprio attraverso il 
contenimento (rinunciando alla MI delle interfaccie, tanto non era quella 
la prerogativa in quel caso), ma la soluzione era talmente farraginosa che 
da allora sono sempre stato un accanito sostenitore della MI 
*dell'implementazione*.
ciao Anto


contenimento (rinunciando alla MI delle interfaccie, tanto non era quella 
Ah ragaaaaaa... si dice "interfacce" non "interfaccie".. ;))
Italian please ;)


 linguaggio in cui queste due cose sono separate.
Ma a un certo punto qualcuno le interfacce deve implementarle. La
possibilita' di ereditare da classi non istanziabili, ma che non sono
interfacce pure e' molto comoda per evitare duplicazione di codice. Io
vedo le interfacce come "ruoli" e mi pare abbastanza naturale che le
diverse implementazioni di ciascun ruolo tendano ad assomigliarsi.
Quando un gruppo di classi ha in comune piu' di un ruolo, se non si puo'
fattorizzarne l'implementazione in una classe base l'unico modo di
raccogliere la funzionalita' a fattor comune e' introdurre un adattatore
e delegare a questo lo svolgimento di tali funzionalita'. Tra parentesi,
non esistendo in Java un meccanismo automatico di delega, il codice
aumenta.
Ciao,
Nicola

 nuovi wrapper.
Questo perche' i linguaggi in questione non mettono a disposizione un meccanismo
di delega. Stai ragionando troppo in termini di C++ o di Java. Io parlavo di un
linguaggio ipotetico che separasse nettamente la gerarchia delle interfacce
(magari con MI) da quella delle implementazioni (strettamente SI). Idealmente
con tipizzazione dinamica e con un meccanismo di delega.


 meccanismo di delega.
cosa intendi di preciso con "meccanismo di delega"? Immagino che sia 
qualcosa di diverso dai "delegate" del C# (altrimenti mi sparo perche' non 
ho capito niente ;-).


 ho capito niente ;-).
Difficle da dire dato che non so nulla dei delegate del C#.
Un meccanismo di delegazione e' un meccanismo per cui:
Un oggetto concreto O che deve implementare un'interfaccia I e che ha accesso ad
un oggetto concreto S (sia per derivazione, che per contenimeno o in altro modo)
il quale a sua volta implementa l'interfaccia I, puo' limitarsi a far si che la
sua implementazione di I corrisponda a quella data da S.
In C++ questo e' possibile (e avviene automaticamente) solo se si ferificano
tutte le seguenti:
1) nessuna delle interfacce di O diverse da I hanno metodi con nome in conflitto
con quelli di I
2) O deriva pubblicamente da S (che ovviamente deriva pubblicamente da I)
3) O non deriva da altre classi che implementano I (nota che se lo facesse in
pratica violerebbe la 1)


 sua implementazione di I corrisponda a quella data da S.
Io avevo anche suggerito una sintassi per il C++, ma non ho avuto molto
seguito:
struct A {
  int f();
};
struct B {
  int g();
};
struct C {
    using a.f;
    using b->g;
  private:
    A a;
    B * b;
};
Dovrebbe permettere:
C c;
c.f();
c.g();
L'eventuale associazione tra una superclasse astratta ed i metodi
delegati sarebbe implicita.
Ciao,
Nicola


 seguito:
Ricordo. E salvo analizzare meglio eventuali implicazioni negative, potrei anche
trovarmi d'accordo. Il fatto e' che non sta a me essere d'accordo ma al comitato
ISO!
Comunque si potrebbe anche permettere:
struct I {  // l'interfaccia
    virtual void foo()=0;
    virtual void bar()=0;
};
struct A: public I {   // concreta che supporta I
    // implementazione di I
    void foo();
    void bar();
};
struct B: public I {   // concreta che supporta I
    A a;
    // implementazione di I
    using a::I;
};


 Difficle da dire dato che non so nulla dei delegate del C#.
Da quello che avevo capito io il delegate in C# e' qualche cosa come un
puntatore a funzione membro di con le seguenti caratteristiche:
1) Non deve essere conosciuta a priori il prototipo della funzione membro,
    quindi cio vuol dire che si possono far puntare di volta in volta
funzioni
    membro completamente diverse (sia per parametri che per valori di
ritorno)
2) Possono indirizzare "contemporaneamente" piu' di una funzione membro, in
questo
    caso tutte le funzioni membro devono avere la stessa signature.
di + nin so.
-- 
Posted from 
dell-01.mm.eutelsat.org
 [194.214.173.17] 
via Mailgate.ORG Server - 
http://www.Mailgate.ORG

 Difficle da dire dato che non so nulla dei delegate del C#.
 
[cut]
ok, era quello che mi ero immaginato. E mi sento anche sollevato, dato che 
non c'entra nulla con i delegate del C# ;-) (che, per la cronaca, sono 
delle specie di puntatori a metodi che memorizzano anche l'istanza sulla 
quale il metodo deve essere eseguito).


 quale il metodo deve essere eseguito).
...Ovvero cio' che in Delphi e BCB si chiama closure.
Ciao,
Nicola

 quale il metodo deve essere eseguito).
Cioe' una cosa simile alla combinazione di std::mem_fun o std::mem_fun_ref o
std::mem_fun1 o std::mem_fun1_ref con std::bind1st ?


 
Credo che la differenza rispetto a una closure che puoi implementare
usando std::mem_fun_t e binder1st, è che il tipo del delegate in C#
dipende soltanto dalla signature del metodo e non dal tipo dell'oggetto
che viene 'bindato'. Questo consente di usare lo stesso delegate per
invocare metodi su oggetti di classi non imparentate tra loro.
Non so se in C++ si riesca a otterne qualcosa di analogo (sempre che io
abbia capito bene come funzionano in C#, cosa di cui non sono sicuro).
Se il numero degli argomenti del metodo è fisso in C++ si potrebbe fare
qualcosa del genere (scritto al volo):
template< class ResultT, class ArgT >
struct delegate_impl_base
{
        virtual ResultT call( ArgT ) = 0;
        virtual ~delegate_impl_base() { }
};
template< class BoundT,  class ResultT, class ArgT >
struct	delegate_impl: public delegate_impl_base<ResultT,ArgT>
{
	typedef  ResultT (BoundT::*mem_func_type )(ArgT) ;
	BoundT*        ptr_;
	mem_func_type  func_;
	delegate_impl( BoundT* ptr,  mem_func_type func )
	: ptr_(ptr), func_(func)
	{
	}
	virtual ResultT call( ArgT arg ) { return (ptr_->*func_)(arg); }
};
template< class ResultT, class ArgT >
struct delegate
{
	delegate_impl_base<ResultT,ArgT>* impl_;
	delegate() : impl_(0) { }
 
	template< class T >
	void set( T* ptr, ResultT ( T::* func )(ArgT)  )
	{
		delete impl_; 
		impl_ = new delegate_impl<T,ResultT,ArgT>( ptr, func);
	}
	ResultT operator() ( ArgT a ) {	return impl_->call(a); }
	~delegate() { delete impl_; }
};
struct A
{
	void pippo(int i ) { cerr << "A::pippo i=" <<i<< endl; }
};
struct B
{
	void pluto(int i ) { cerr << "B::pluto i=" <<i<< endl; }
};
typedef delegate<void,int>	void_int_delegate;
int main()
{
	void_int_delegate d;
 
	A a;
	B b;
	d.set( &a, &A::pippo );
	d(10);
	d.set( &b, &B::pluto );
	d(20);
}
Per rendere le classi delegate<> copiabili direi che basta aggiungere un
metodo clone() all'interfaccia definita da delegate_impl_base<>.
Max

 
[implementazione di closure "snippata"]
Il problema e' che le closure Borland sfruttano l'associazione di un
puntatore a oggetto ed un puntatore a membro funzione: con questi due
oggetti conoscere la classe a cui appartengono non e' necessario per
invocare il metodo. Il risultato e' un meccanismo decisamente
efficiente. La tua implementazione e' invece "pesantuccia", benche' sia
a mio avviso quanto di meglio si possa fare nell'ambito del linguaggio
standard.
Passando al filosofico, da un certo punto di vista le closure
riempirebbero un vuoto di simmetria nel linguaggio. Se abbiamo
int f() { return 2; }
struct C { int g() { return 3; } };
C c;
Se f e' un puntatore a funzione e &C::g e' un puntatore a membro
funzione, perche' c.g non e' qualcosa di utilizzabile?
Ciao,
Nicola


Che tu sappia, ci sono mai state proposte (e discussioni) a questo
riguardo su comp.stc.c++?
Max


Non so se l'alternativa che ti propongo sia in qualche
modo implementation dependent (e` sempre possibile un
reinterpret_cast tra puntatori a funzioni membro di
oggetti diversi?).
Comunque, testata con il tuo esempio (pippo/pluto) sul
BCB5 e sul g++ 2.95 e g++ 3.01 su Linux-mdk, funziona.
template< typename ResultT, typename ArgT >
struct delegate
  { typedef  ResultT ( delegate::* func_t)( ArgT );
    template< class BoundT >
    void bind( BoundT* ptr, ResultT (BoundT::*memfunc )( ArgT) )
      { func_ = reinterpret_cast<func_t>( memfunc );
        obj_  = reinterpret_cast<delegate*>(ptr); }
    ResultT operator()( ArgT a )
      { return (obj_->*func_)( a ); }
  private:
    func_t       func_;
    delegate*    obj_; };
Confesso di non avere capito quando dovrebbe essere
efficiente usare i delegate ...
ciao
Massimo

 efficiente usare i delegate ...
Credo costrutti di questo tipo (implementati in qualche modo o disponibili
come feature built-in del linguaggio) offrano un vantaggio nelle
prestazioni se sono in grado di risolvere il binding dinamico dei metodi
virtuali al momento dell'assegnamento della coppia oggetto/metodo e non in
fase di chiamata del metodo.
La tua implementazione (e anche la mia) sembra funzionare anche con i
metodi virtuali, sebbene non mi sia chiarissimo come questo sia possibile.
Max

 metodi virtuali, sebbene non mi sia chiarissimo come questo sia possibile.
Non le ho guardate a fondo. La tua funziona semplicemente perche' il binding
delle funzioni virtuali lo fa a call-time e non a bind time (a parte il fatto
che se usi una estensione specifica di un linguaggio, il fatto che funzioni
significa solo che l'estensione e' implementata correttamente).
La sua funziona solo per caso e mi stupisce che funzioni su piu' di un
compilatore, IMO il funzionamento non e' affatto garantito. Soprattuto se
coinvolgi meccanismi interni come le funzioni virtuali e l'eredità multipla
virtuale.



Probilmente tutti i compilatori esaminati implementano i puntatori a
funzioni membro virtuali mediante puntatori a funzioni che effettuano
internamente il dispatching via vtable.
Max

 internamente il dispatching via vtable.
Direi che e' il tipo di puntatore che lo fa. La sintassi stessa ti dice che stai
puntando ad un membro e un puntatore ad un membro virtuale e' strutturato
diversamente da un puntatore ad un membro non virtuale. Quindi non serve
generare uno stub (o meglio, viene generato inline il codice relativo nel punto
in cui dereferenzi il puntatore).


 inline il codice relativo nel punto in cui dereferenzi il puntatore).
In effetti č cosě, almeno sotto gcc, dato che i puntatori a membri hanno
sizeof di 8 byte, che suggerisce che contengano piů informazioni di un
puntatore a funzione. In effetti, esaminandoli internamente, ho visto che
contengono un puntatore a una funzione nel caso di metodi non virtuali
oppure una sorta di indice nel caso di metodi virtuali. Se anche gli altri
compilatori usano questa tecnica non mi stupisce a questo punto che
l'implementazione di Massimo Valentini funzioni correttamente anche su
altre piattaforme e anche con metodi virtuali.
Max

 altre piattaforme e anche con metodi virtuali.
Si. Credo di poter dedurre che delle due implementazioni proposte, una funzioni
per merito di una estensione del linguaggio (e a questo punto e' possibilissimo
che il lookup della v-tbl avvenga a bind time e si presuppone che la cosa
funzioni in tutti i casi, quindi anche per le basi virtuali), l'altra funzioni
per puro caso. In realtà la seconda non funziona per caso a causa
dell'implementazione dei puntatori a membro che e' fatta nello stesso modo (o in
modo simile) sui vari compilatori. Funziona proprio per caso perche' di fatto
corrisponde a un undefined behaviour.


 corrisponde a un undefined behaviour.
Unspecified: 5.2.10.9 (del draft pre-votazione)
Bisognerebbe fare un secondo reinterpret_cast sia per l'oggetto che
per il puntatore a funzione per rientrare nello specified, perdendo
tutta l'efficienza, dovendo conoscere il tipo dell'oggetto anche al
momento della chiamata.
Ma, evidentemente, con le cautele dell'unspecified, nelle
implementazioni che ho testato il reinterpret_cast e` solo 'formale'.
(Per curiosita` ho provato a chiamare metodi di una classe con
puntatore ad oggetti di un'altra, entrambe con una sola std::string
come dato e funziona).
Per completezza, il delegate che ho postato ieri lo avevo provato con
l'esempio (A::pippo/B::pluto) che non prevedeva metodi virtuali. Per
funzionare anche con i metodi virtuali bisogna aggiungere un metodo
virtuale fittizio alla classe delegate, altrimenti il g++ 2.95 da`
un segmentation fault.
ciao
Massimo

 
Ecco un'altra variante sul tema.
Quella che segue non dovrebbe fare affidamento su estensioni o su dettagli
"unspecified". (Mi pare comunque che abbia prestazioni peggiori rispetto a
quella di Massimo: una chiamata a funzione in più).
  template< class T,    class ResultT, 
           class ArgT, ResultT( T::*MemFunc)(ArgT) >
  ResultT call_memfunc( void* p, ArgT a )
  {
	return (reinterpret_cast<T*>(p)->*MemFunc)(a);	
  }
  template< class ResultT, class ArgT >
  class delegate
  {
	typedef ResultT( * func_t)( void*, ArgT );
	void*  obj_;	
	func_t func_;
	public:	
	template< class T, ResultT( T::* MemFunc )(ArgT) >
	 void bind( T* p )
	 {
		 obj_ = p;
		 func_ = &call_memfunc<T,ResultT,ArgT,MemFunc>;
	 }	 
	ResultT operator()( ArgT a ) { return func_( obj_, a ); }
 };
 
  A a;
  delegate<void,int> d;
  d.bind<A,&A::pippo>(&a);
   // oppure (gcc esige quest'altra sintassi):
   d.template bind<A,&A::pippo>(&a);
Max