Newsgroup: it.comp.lang.c++
Titolo: Derivare con virtual

Ho visto questo esempio:
class A
{
    ...
}
class B: public virtual A
{
    ...
}
La mia domanda č: virtual lassů ?!? :-) A che serve?
--
Stefano

 La mia domanda è: virtual lassù ?!? :-) A che serve?
Detta cosi non serve a nulla.
Se tu avessi ad esempio una gerarchia del tipo:
struct A { int a; };
struct B :  A { int b; };
struct C:  A { int c };
struct D :  B, C { int d; };
ti troveresti nella struttura di D due volte le strutture di A
una la erediti da B e l'altra da C.
Primo problema:
    A cosa accedi se scrivi:   D::a ?
Secondo problema:
    Se A fosse una struct grossa puoi capire che la duplicazione di
D avrebbe un inutile storage overhead, per non parlare del pericolo
di avere due istanze di A inconsistenti.
Questa sorta di "sharing inheritance" e stata chiamata "virtual
inheritance", che e' comunque piu' pesante da implementare,
infatti con una inheritance "normale" le classi basi (embedded)
e le derivate possono condividere un comune "address point"
(questo vale per le derivazioni singole e per la classe base
piu' a sinistra per le multiple) o un displacement costante
(questo per le derivazioni multiple tranne che per la classe
piu' a sinistra).
Derivazione singola (sto facendo esempi con le struct
per evitare problemi di accesso)
struct A {
    int a;
    void aF();
};
se scrivi:
    A* pA;
    pA->a;    // *(pA+dAa);
il commento indica come si accede all'elemento "a"
e dAa e' il displacement fisso di "a" dentro A.
Con una derivazione
struct B : A{
    int b;
    void bF()'
};
B* pB;
pB->b;    // *(pB + dBb);
pB->a     //  *(pB + dBA + dAa);   >  *(pB + dAa);
dove dBA e' il displacement della struttura embedded A
dentro B. Per motivi di performance spesso e volentieri
(vedi Visual C++) le implementazioni dei compilatori
hanno dBA  0
con la multipla si fanno discorsi analoghi con la limitazione
che solo una delle classi embedded ha il displacement
dentro la classe che la ospita pari a 0.
Con la derivazione virtuale tutti questi discorsi falliscono
le classi ereditate virtualmente invece che avere un
displacement nullo rispetto alla classe che la ospitano
sono poste invece alla fine (implementazione di M$).
Purtroppo all'interno della classe D le due classi embedded
B e C non sanno come accedere ai membri della
classe A (considera che le classi vengono compilate
senza sapere di come verrano ereditate) perche'
la classe D ora ha una sola istance di A, quindi serve
ora un meccanismo per far si che ogni classe con una base
virtuale possa calcolare la locazione della classe virtuale
all'interno delle sue derivate ( come ho detto prima ad
esempio B al momento della compilazione
non sa come verra' ereditata).
Tutto questo si risolve inserendo in ogni classe con una
base virtuale un puntatore vbptr ("virtual base table pointer")
che punta ad un'area condivisa (una tabella) di offset
(a partire dalla locazione di memoria che ospita vbprt)
per ragiungere la base virtuale.
Nel mio esempio iniziale:
D* pD;
pD->a;    // *(pD + dDBvbptr + (*(pD+dDBvbptr))[1] + dAa);
pD->b;    // *(pD +dDB + dBb);
pD->c;    // *(pD +dDC + dCc);
pD->d;    // *(pD + dDd);
dove DBvbptr e' il displacement di vbptr dentro B.
Spero di essere stato preciso ed esauriente.
Ciao
Gaetano.
-- 
Posted from 
dell-01.mm.eutelsat.org
 [194.214.173.17] 
via Mailgate.ORG Server - 
http://www.Mailgate.ORG

la classe D ora ha una sola istance di A
Non capisco come possa funzionare. Anche se D, mettiamo, non deve accedere a
niente, quando B e C lavorano su membri di A dovrebbero farlo ognuna con una
loro A "privata". Se A::a è condiviso, se della class B faccio B::a++
l'effetto si ripercuote anche su C::a, senza che la classe C se ne accorga.
Onestamente non ho capito molto bene, specialmente la storia del late binding
con la tabella di puntatori.
--
Stefano

 con la tabella di puntatori.
I mebri di A stanno in fondo all'istanza di D, peccato che B e C non sanno
come verrano derivate, quindi come faranno in futuro a sapere dove e'
finito il loro pezzo "A" ? Fanno entrambe riferimento al puntatore vbptr
che hanno alla loro fine per accedere ad A ed e' il compilatore
che quando costruisce D a mettere la roba giusta dentro i puntatori
per far puntare la tabella giusta.
Se la spiegazione non dovesse ancora essere chiara mi impegno
a rifare un altro post cercando di essere piu' chiaro.


 l'effetto si ripercuote anche su C::a, senza che la classe C se ne
accorga.
Se è questo che pensi, non usare la derivazione virtuale. Se invece
pensi che l'istanza di B, quella di C e quella di D debbano avere una
istanza di A che è in comune e che le modifiche fatte da una qualunque
delle classi debbano essere visibili a tutte le altre ... allora usi
virtual.
--
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