Newsgroup: it.comp.lang.c++
Titolo: Inside the C++ Object Model

"In the case of virtual inheritance, only a single occurrence of the base
class is maintained (called a subobject) regardless of how many times the
class is derived from within the inheritance chain. Iostream, for example,
contains only a single instance of the virtual ios base class."
Riporto una parte del testo di Inside the C++ Object Model che sto provando
a leggere (nonostante il mio pessimo inglese... :().
L'ereditarietà virtuale (se cosi si dice...) non l'ho mai affrontata, mi
farebbe comodo
avere qualche chiarimento in proposito ed in particolare sull' affermazione
di Lippman.
Ciao
Terenzio

sull' affermazione di Lippman.
Certo, chiedi pure.  Cosa non ti e` chiaro...?
"Concettualmente" (anche se oggi, in pratica, l'implementazione
dell'eredita` virtuale e` fatta con maggior efficienza usando la
vtbl), immagina che ogni classe che ha una base virtuale, invece
di una "copia" dei campi-dati di quella base al proprio interno,
abbia entro si se` un "puntatore" a un oggetto di quel tipo.  Se
quel tipo entra come base virtuale piu` volte in una eredita`
multipla, i vari "punti" in cui viene visto come base hanno tutti
puntatori allo *stesso* oggetto di quel tipo; cosi`, appunto
come scrive Lippmann, c'e` una singola istanza della classe
base ("sub-oggetto") per quante volte possa apparire nella
gerarchia di eredita` multipla.
Un oggetto puo` facilmente trovare la sua base virtuale (basta
seguire il puntatore), ma il percorso inverso non e` cosi`
facile -- i cast alla C, e static_cast, non sono in grado di farlo;
se hai la necessita` di "cast all'indietro" dalla base virtuale
a una classe derivata, devi farlo sfruttando la run-time type
identification, e specificamente con dynamic_cast.
Poni pure qualsiasi domanda sul gruppo, e vedrai che le
risposte e i chiarimenti non mancheranno!
Alex

risposte e i chiarimenti non mancheranno!
Pensa che sono solo al primo capitolo..... ;)
Ciao
Terenzio

libreria. Sapete dove trovarne?
http://www.desy.de/user/projects/C%2b%2b.html
e` la URL della "C++ Virtual Library" (i %2b sono codifiche
"sicure" per caratteri "+", questione di purismo HTML:-),
sotto "free packages" troverai un primo elenco di librerie
gratuite per C++, e un link alla "review of C++ libraries"
per trovarne tante, TANTE altre.
Comunque, un esempio semplice e` l'idioma "mix-in".
Supponiamo di avere una classe base astratta, tipo:
    class emittore {
    public:
        virtual void emetti(const std::string&) = 0;
    };
le implementazioni di questa incapsulano il concetto di
"emettere una riga" (magari la scrivono con iostream,
magari la mandano ad un log di sistema, e/o la mostrano
in una finestra su schermo, e cosi` via).
Il modo piu` normale per connettere del codice "cliente"
alla implementazione concreta di questa classe e` passare
al cliente un puntatore a emittore, a cui deleghera` in
modo esplicito l'output:
    class chiaccherone {
        emittore* pEm;
    public:
        chiacchierone(emittore* pEm): pEm(pEm) {}
        void parla() {
            pEm->emetti("Ciao!");
            // 998 linee omesse
            pEm->emetti("OK, basta.");
        }
    };
da usarsi ad esempio con:
        // si suppone: class emittore_su_stream: public emittore &c &c
        emittore_su_stream ess(std::cout);
        chiacchierone ciac(&ess);
        ciac.parla();
Supponiamo, pero`, che per qualche buona e valida
ragione scegliamo invece di fare la connessione con
l'uso dell'eredita` multipla (non mi fare partire anche
sul tema "in quali condizioni e` meglio usare l'eredita`
dell'incapsulamento" che non finisco piu`... Herb Sutter
ha una bella serie di articoli in merito su C++ Report,
in corso di pubblicazione, molto consigliabili).
Allora, dovremo usare emittore come base virtuale:
    class emittore_su_stream: public virtual emittore { // ecc ecc
    class chiacchierone_2: public virtual emittore {
    public:
        void parla() {
            emetti("Ciao!");
            // 998 linee omesse
            emetti("OK, basta.");
        }
    };
    class cliente_connettore: public emittore_su_stream, public
chiacchierone_2 {
    public: cliente_connettore(std::iostream& x): emittore_su_stream(x) {}
    };
Adesso, l'uso diverra`:
    cliente_connettore x(std::cout);
    x.parla();
Come vedi, l'eredita` multipla (con base virtuale) ottiene risultati
analoghi alla connessione esplicita ma _con una fusione di identita`_
fra 'cliente' dell'emittore (il 'chiacchierone') e 'servente' della stessa
base astratta (l'emittore_su_stream).  Normalmente non e` una
gran bella alternativa perche` si riduce la flessibilita`, ma a volte
e` proprio questo "fissaggio compile-time" quello che desideriamo
(soprattutto se vogliamo parametrizzarlo in un template).
Che la base virtuale sia una base astratta pura (una "interfaccia",
o come alcuni anche dicono [secondo me falsando un poco la
terminologia piu` usuale] una "classe-protocollo") e` MOLTO
tipico; e` possibile costruire esempi in cui ha senso avere una
base virtuale che non e` puramente astratta (sostanzialmente
per una scelta di centralizzare uno "stato" -- ma normalmente,
questo "stato" se ne starebbe meglio in una classe mixin, con
i suoi accessori nella base astratta pura che fa da base virtuale),
ma si tratta, cosi` a ocio, di meno del 5-10% dei casi REALI di
uso di questo costrutto gia` un po' astruso.
Alex

Sapete dove trovarne?
Posso inviarti i sorgetti di una gerarchia di classi in cui ereditarieta` multipla ed
ereditarieta` virtuale mi hanno permesso di riutilizzare nell'estensione di una classe
codice scritto per l'altro ramo della gerarchia.
Paolo
----------------------------------------------------------
  Paolo Marotta
  Computer Science, University of Pisa
  home:   
http://www.cli.di.unipi.it/~marotta
  e-mail: 
mar...@cli.di.unipi.it
 
----------------------------------------------------------