Newsgroup: it.comp.lang.c++
Titolo: Componenti in C++

Mi chiedevo se qualcuno conoscesse un modo per costruire componenti con
interfaccie con metodi in comune ma con implementazioni differenti senza
dover ricorrere a derivazione multipla virtuale.
Mi spiego meglio:
Dato un componente (chiamiamolo COggetto tanto per intenderci) si vuole che
le interfaccie che espone (ad esempio ISicura e IVeloce) abbiano uno o piu'
metodi in comune (metodo Rilascia() ad esempio) ma con implementazioni
differenti (quello di ISicura pieno di controlli, quello di IVeloce
assolutamente privo).
bene finora sono riuscito a fare questa cosa (in C++) nel seguente modo:
campi del componente in una classe che chiamiamo COggetto_BASE:
class COggetto_BASE
{
     public:
     INT32 iValue;
};
le due interfaccie ovviamente come classi astratte:
class ISicura
{
    public:
    virtual void Rilascia() PURE;
};
class IVeloce
{
    public:
    virtual void Rilascia() PURE;
};
due classi che implementano l'interfaccia e derivano virtualmente dalla
base:
class COggetto_ISicura_IMP : ISicura, virtual COggetto_BASE
{
    public:
    void Rilascia();
};
class COggetto_IVeloce_IMP : IVeloce, virtual COggetto_BASE
{
    public:
    void Rilascia();
};
ed infine il componente vero e proprio ottenuto derivando dalle due
implementazioni:
class COggetto : public COggetto_ISicura_IMP, COggetto_IVeloce_IMP
{
};
Ora il problema e' che ereditarieta' virtuale multipla significa un mare di
deferenziamenti ad ogni accesso ad un membro della classe quando poi non ce
ne sarebbe effettivamente bisogno per cui la soluzione di cui sopra non e'
realisticamente praticabile in un programma serio.
Ringrazio fin da ora chiunque sia in grado di spiegarmi una maniera piu'
elegante (meno pesante!!!) di realizzare la stessa cosa...
feedb...@yahoo.com

 dover ricorrere a derivazione multipla virtuale.
... snip spiegazione e codice
Puoi provare cosi':
class ISicura {
public:
    virtual void Rilascia() PURE;
};
class IVeloce {
public:
    virtual void Rilascia() PURE;
};
class ISicura_S : public ISicura {
public:
    virtual void SRilascia() PURE;
    virtual void Rilascia() { SRilascia(); }
};
class IVeloce_V : public IVeloce {
public:
    virtual void VRilascia() PURE;
    virtual void Rilascia() { VRilascia(); }
};
 class COggetto : private ISicura_S, private IVeloce_V
{
public:
    void VRilascia() { /* bla bla */ }
    void SRilascia() { /* bla bla */ }
    IVeloce& asVeloce() { return *this; }
    const IVeloce& asVeloce() const { return *this; }
    ISicura& asSicura() { return *this; }
    const ISicura& asSicura() const { return *this; }
public:
    INT32 iValue;
};
--
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

 senza dover ricorrere a derivazione multipla virtuale.
Be' puoi usare i template e l'aggregazione, risparmi nel numero di 
classi da scrivere, e guadagni in facilita' di estensione delle 
interfacce e delle basi
suppongo che Rilascia() usi i dati della classe base
template< typename Base >
class ISicura {
// ...
    public:
    virtual void Rilascia(Base& b);
}    
template< typename Base >
class IVeloce {
// ...
    public:
    virtual void Rilascia(Base& b);
};
template < typename Interface, typename Base >
class COggetto_imp{
  Interface I<B>;
  Base      B;
  public:
  Rilascia() {
    I.Rilascia(B);
  }
};
mi sembra quanto di piu' "modulare" si possa ottenere, basta cambiare 
base e interfaccia, purche' la signature degli oggetti resti comune
un'altra soluzione potrebbe essere quella di usare oggetti funzione, se 
l'interfaccia ha solo il compito di rilasciare le risorse

 realisticamente praticabile in un programma serio.
Hai fatto delle misurazioni? In genere programmi che non hanno vincoli
temporali stretti o cicli con numeri elevatissimi di iterazioni non
hanno alcun degrado prestazionale percettibile legato alla
dereferenziazione implicita nell'eredita' multipla virtuale.
Ciao,
Nicola

Beh vi ringrazio per l'idea ma viola chiaramente il concetto di interfaccia
cosi come e' descritto nella documentazione di COM e CORBA, o in qualsiasi
altro modello a componenti (implementazione dei JavaBeans compresa)
un'interfaccia non ha nulla a che fare con i template, e' semplicemente una
classe i cui metodi siano tutti virtuali puri, e visto che deve poter
funzionare anche con codice scritto in un qualsiasi altro linguaggio e
soprattutto deve funzionare anche su oggetti che non allochiamo noi e di cui
il compilatore ignora quindi totalmente la struttura, di sicuro non puo'
essere un template o avere riferimenti alla classe con l'implementazione
effettiva.
Grazie lo stesso
Feedb...@yahoo.com

 interfaccia 
ne sei proprio sicuro?
pensaci meglio, soprattutto nell'implementazione dei template...

"ciro e luisa" ha scritto:
per qualche spunto:
http://www.cuj.com/experts/1904/vinoski.htm?topic=experts&topic=experts

ci ho pensato...si, e ne sono proprio sicuro...l'idea di andrea ferro e'
credibile e non ha un gran peso in termi di overhead (giusto il doppio di
una chiamata virtuale standard), mentre la vostra viola brutalmente il
concetto di interfaccia COM e l'articolo ne e' anche una conferma [testuale:
A less flexible approach is to instead make the skeleton class a template]
qualora ce ne fosse bisogno...
feedb...@yahoo.com

"FeEdBaCk79" ha scritto:

1 - meno flessibile non vuol dire (testuale)
  "viola chiaramente il concetto di interfaccia cosi come e' descritto 
  nella documentazione di COM e CORBA, o in qualsiasi altro modello a 
  componenti "
2 - la frase che citi si riferisce al fatto di non poter usare funzioni 
membro template virtuali (14.5.2.3), non al fatto che il template sia 
un approccio poco flessibile. e infatti piu' avanti l'articolo dice:
Note also that this approach allows us to once again use default 
arguments for the template parameters. Using defaulted template 
parameters, which isn't allowed with the member template approach, 
helps make this approach easy to use.
non riportare solo quel che ti fa comodo ;)
Il tutto e' "perfettamente" compatibile con l'interfaccia Corba e COM, 
dato che ATL e' basata sui template, e come si legge su ATL Internals 
di Addison Wesley : " Microsoft's Active Template Library (ATL) is a 
framework for generating C++/COM code"
mi spieghi perche' secondo te invece non lo e'?

Ok, quando e' troppo e' troppo:
invece di citare libri, articoli, presidenti del consiglio etc etc.
riguardati:
A) la mia domanda
B) la tua risposta
A) Dato un componente (chiamiamolo COggetto tanto per intenderci) si vuole
che
le interfacce che espone (ad esempio ISicura e IVeloce) abbiano uno o piu'
metodi in comune (metodo Rilascia() ad esempio) ma con implementazioni
differenti (quello di ISicura pieno di controlli, quello di IVeloce
assolutamente privo). [citato pari pari dalla mia prima mail]
questa era la mia domanda... a renderla piu' chiara c'era anche un pezzo di
codice per far capire cosa si voleva alla fine usare e cioe' le due
interfacce e NULL ALTRO visto che un compenente COM (tanto per citarne uno)
non si alloca mai direttamente, anzi in teoria se ne ignora TOTALMENTE
STRUTTURA E DIMENSIONE
quindi in un client finale alla fine ci vanno solo queste due cose
class ISicura
{
    public:
    virtual void Rilascia() =0;
};
class IVeloce
{
    public:
    virtual void Rilascia() =0;
};
e si vuole poter scrivere codice come:
ISicura* s=(ISicura*) QueryInterface(bla bla bla bla);
IVeloce* v=(IVeloce*) QueryInterface(bla bla bla bla 2);
s->Rilascia();
v->Rilascia();
ecco la tua risposta:
B)





  public:
  Rilascia() {
    I.Rilascia(B);
  }
};


[citato altrettanto pari pari dalla tua risposta]
tralasciando il fatto che cosi come e' scritto non compila nemmeno a pagare
oro (passi il punto e virgola che manca ma la SINTASSI dei template e'
sbagliata.)
E:\components\main.cpp(121) : error C2143: syntax error : missing ';' before
'<'
        e:\components\main.cpp(128) : see reference to class template
instantiation 'COggetto_imp<Interface,Base>' being compiled
e:\components\main.cpp(121) : error C2059: syntax error : '<'
        e:\components\main.cpp(128) : see reference to class template
instantiation 'COggetto_imp<Interface,Base>' being compiled
e:\components\main.cpp(121) : error C2238: unexpected token(s) preceding ';'
        e:\components\main.cpp(128) : see reference to class template
instantiation 'COggetto_imp<Interface,Base>' being compiled
e:\components\main.cpp(127) : warning C4183: 'Rilascia': member function
definition looks like a ctor, but name does not match enclosing class
        e:\components\main.cpp(128) : see reference to class template
instantiation 'COggetto_imp<Interface,Base>' being compiled
Error executing cl.exe.
components.exe - 3 error(s), 1 warning(s)
[Citato testualmente da un "tentativo di compilata" con Microsoft Visual C++
6.0]
ma poi le due implementazioni differenti che fine hanno fatto?
volevo venirti incontro e provare (dopo aver corretto il sorgente), mi sono
detto forse sono io che sbaglio, ma provare cosa? le implementazioni dove
vanno piazzate?
non in COggetto_imp perche' c'e' gia...ok allora dove?
in quelle che TU chiami interfacce ISicura e IVeloce? se le metto li in
quanto implementazioni SUPPONGO che dipendano dal contenuto effettivo di
base...e allora che me ne faccio di base come template? sempre ammesso e non
concesso che poi il tutto funzioni...
e comunque dove e' il supporto CONTEMPORANEO sulla STESSA base a TUTTE E DUE
le interfacce? se COggetto_imp e' parametrizzato per UNA interfaccia...lo
parametrizzo per SETTANTA se voglio supportarne di piu'? cosi risparmio di
scrivere classi e codice come tu hai detto nella tua risposta?
quasi sicuramente sono io che non ho capito quello che tu hai scritto
o forse sei tu che non mi hai saputo spiegare,
per fugare questo dubbio io allora ti ripeto la domanda:
voglio costruire un componente usando il C++
che mi permetta nel client di scrivere SOLO E SOLAMENTE
class ISicura
{
    public:
    virtual void Rilascia() =0;
// ed altri metodi ovviamente
};
class IVeloce
{
    public:
    virtual void Rilascia() =0;
// idem con patate
};
void main()
{
ISicura* s=(ISicura*) QueryInterface(bla bla bla bla);
IVeloce* v=(IVeloce*) QueryInterface(bla bla bla bla 2);
s->Rilascia();
v->Rilascia();
}
e vedere chiamati due metodi diversi che pero' operino sullo stesso
componente (oggetto o chiamalo come vuoi...la stessa zona di memoria
ecco...mettiamo un int nella base e da ISicura lo si mette a 0 da IVeloce lo
si
mette a 1 ok?)
il tutto senza usare derivazione virtuale multipla perche' cosi ci riesco
anche da solo senza leggere giornali...
Se sei in grado di rispondermi con un pezzo di codice comprensibile che
compili (e soprattutto che funzioni) prima ti ringrazio, poi mi tolgo il
cappello,
mi inchino e ti pago pure pizza e birra a Te e a Luisa.
in caso contrario credo che sia inutile continuare a sprecare corrente
elettrica in risposte
e contro risposte a chi mette da sopra e a chi mette da sotto a leggiti
questo e leggiti
quello perche' tanto mi sembra che qui alla fine non si vinca nulla.
ringraziandoti comunque per l'interesse 
feedb...@yahoo.com
P.S. sono curioso di conoscere la tua soluzione basata su oggetti funzione:
"un'altra soluzione potrebbe essere quella di usare oggetti funzione, se
l'interfaccia ha solo il compito di rilasciare le risorse" [sempre citato
testualmente...ah e comunque no, l'interfaccia non ha il solito compito di
rilasciare le risorse...Rilascia era semplicemente il primo nome che mi era
venuto in mente per un metodo ma credo che si intuisse anche dalla mia
domanda...]

Ok, quando e' troppo e' troppo:
invece di citare libri, articoli, presidenti del consiglio etc etc.
riguardati:
A) la mia domanda
B) la tua risposta
A) Dato un componente (chiamiamolo COggetto tanto per intenderci) si vuole
che
le interfacce che espone (ad esempio ISicura e IVeloce) abbiano uno o piu'
metodi in comune (metodo Rilascia() ad esempio) ma con implementazioni
differenti (quello di ISicura pieno di controlli, quello di IVeloce
assolutamente privo). [citato pari pari dalla mia prima mail]
questa era la mia domanda... a renderla piu' chiara c'era anche un pezzo di
codice per far capire cosa si voleva alla fine usare e cioe' le due
interfacce e NULL ALTRO visto che un compenente COM (tanto per citarne uno)
non si alloca mai direttamente, anzi in teoria se ne ignora TOTALMENTE
STRUTTURA E DIMENSIONE
quindi in un client finale alla fine ci vanno solo queste due cose
class ISicura
{
    public:
    virtual void Rilascia() =0;
};
class IVeloce
{
    public:
    virtual void Rilascia() =0;
};
e si vuole poter scrivere codice come:
ISicura* s=(ISicura*) QueryInterface(bla bla bla bla);
IVeloce* v=(IVeloce*) QueryInterface(bla bla bla bla 2);
s->Rilascia();
v->Rilascia();
ecco la tua risposta:
B)
Be' puoi usare i template e l'aggregazione, risparmi nel numero di





  public:
  Rilascia() {
    I.Rilascia(B);
  }
};


[citato altrettanto pari pari dalla tua risposta]







class ISicura
{
    public:
    virtual void Rilascia() =0;
// ed altri metodi ovviamente
};
class IVeloce
{
    public:


s->Rilascia();
v->Rilascia();
}




"un'altra soluzione potrebbe essere quella di usare oggetti funzione, se



Invece di inveire studia un po il C++ e se qualcuno
posta una soluzione senza compilarla, afferra il concetto di
quello che voleva dire. Non piangere che ti posto io la versione che
compila,
per ovvi motivi non ti posto anche il makefile (OT).
//----------------------------- CUT HERE -------------------------------
#include <stdio.h>
#include <iostream>
template< typename Base >
class ISicura {
// ...
    public:
    virtual void Rilascia(Base& b)  { }
};
template< typename Base >
class IVeloce {
// ...
    public:
    virtual void Rilascia(Base& b) { }
};
template < typename Interface, typename Base >
class COggetto_imp{
  Interface I;
  Base      B;
  public:
  void Rilascia() {
    I.Rilascia(B);
  }
};
class COggetto {
};
int main(){
        COggetto_imp<IVeloce<COggetto>, COggetto > obj;
}
//----------------------------- CUT HERE -------------------------------
Contento ora? Non so se fa esattamente quello che ti serviva, ripeto
"Non so se fa esattamente quello che ti serviva",
ma se osservi le differenze tra il codice postato in precedenza e quello
qui ti accorgi che erano delle dimenticanze.
C'e' un modo anche per evitare di specificare due volte COggetto
quando costruisci un obj,  ma il tuo VC++ non accetta i  template template,
e poi
sinceramente anche con il GCC3.0 non ci sono riuscito...... :-(
dovrei andare a scartabelare qualche codice che ho scritto tempo fa.
Ciao Gaetano.
PS: Che ne diresti di applicare la patch (per il RE) al tuo FuoriGuarda , o
a
cambiare News Reader ?
-- 
Posted from 
dell-01.mm.eutelsat.org
 [194.214.173.17] 
via Mailgate.ORG Server - 
http://www.Mailgate.ORG

 a cambiare News Reader ?
parole sacrosante.
Ciao Maurizio.

 inutile commentare per il makefile.
ok ok     Makefile     :-)
