Newsgroup: it.comp.lang.c++
Titolo: ereditarieta multipla, e i costruttori al centro del 'diamante'

sto leggendo il cap 6 di Thinking in C++ Vol 2.
ecco l'esempio:
class MBase {
public:
    MBase(int) { }
};
class D1 : virtual public MBase { ... };
class D2 : virtual public MBase { ... };
class MI : public D1, public D2
{
public:
    MI() : MBase(3) { }
};
praticamente dice che se si usano le "virtual base classes", nel costruttore
dell'ultima derivata devo provvedere IO all'inizializzazione di tutto quanto
(quindi il costruttore di D1, D2 e MBase non viene chiamato).
1° domanda:
la keyword virtual funziona coma al solito? ovvero in MI, D1 e D2 vengono
sempre ereditate come virtual?
2° domanda:
la risoluzione di scope va bene per chiamare i costruttori delle classe
intermedie (D1 e D2)? cioè:
    MI() : D1(4), D2(4), ... { }
e che succede se entrambe (D1 e D2) nel loro costruttore chiamano
MBase::MBase?
all'inizio del capitolo Eckel diceva che con l'ereditarietà multipla, con
questo esempio del diamante, si avevano due sub-oggetti MBase, ma pensavo
fosse riferito solo al fatto che ci siano 2 VTABLE. è così?
grazie e scusate la lunghezza del post.
ciao :: xaero

 ma pensavo fosse riferito solo al fatto che ci siano 2 VTABLE. è così?
Non sono sicuro di come venga implementato l'inoltro di chiamate
virtuali nel caso di eredita' multipla.
Ciao,
Nicola

 virtuali nel caso di eredita' multipla.
Funziona cosi':
Nota: quanto segue non e' richiesto dallo standard ma e' una implementazione
possibile dello stesso.
struct B {
    virtual ~B();
};
struct M1: public B {
};
struct M2: public B {
};
struct D: public M1, public M2 {
};
ovvero il caso di dervazione multipla non virtuale.
- La classe B ha un vtbl_ptr che punta a una vtbl.
- La classe M1 contiene un oggetto B avente il suo stesso indirizzo. C'e' un
vtbl_ptr che punta a una vtbl.
- Idem la classe M2.
- La classe D contiene un oggetto M1 avente il suo stesso indirizzo (e che a sua
volta contiene un oggetto B allo stesso indirizzo) e poi contiene un oggetto M2
(che a sua volta contiene un oggetto B distinto, pertanto in D ci sono due B
distinti) avente stessa identita' ma indirizzo diverso. Ci sono due vtbl_ptr che
puntano a due vtbl diverse (ma ovviamente equivalenti).
struct B {
    virtual ~B();
};
struct M1: virtual public B {
};
struct M2: virtual public B {
};
struct D: public M1, public M2 {
};
ovvero il caso di dervazione multipla virtuale (il diamante).
- La classe B ha un vtbl_ptr che punta a una vtbl.
- La classe M1 NON contiene un oggetto B. Contiene un puntatore ad un oggetto B.
L'oggetto B puo' esistere nello stesso indirizzo di M1 o meno. L'oggetto B
esiste sempre e fa parte dell'oggetto (e ne ha persino l'identità). Ma non e'
detto che, strutturalmente, si trovi all'interno di M1. C'e' un vtbl_ptr che
punta a una vtbl e c'e' un puntatore speciale (chiamiamolo vb_ptr) che punta
all'oggetto B. Se vb_ptr!=this allora c'e' anche un secondo vtbl_ptr che punta a
una seconda vtbl.
- Idem la classe M2.
- La classe D contiene un oggetto M1 avente il suo stesso indirizzo e poi
contiene un oggetto M2. Ci sono due vtbl_ptr che puntano a due vtbl diverse. Ci
sono anche i due vb_ptr che pero' puntano allo stesso oggetto B. Se l'indirizzo
dell'oggetto B e' diverso da entrambe gli indirizzi (D::M1 e D::M2, dove D::M1
ha lo stesso indirizzo di D) allora esiste anche un terzo vtbl_ptr che punta ad
una terza vtbl.
Detto questo, come funzionano le funzioni virtuali? Semplice: a seconda di quale
puntatore viene usato per chiamarle viene eseguita la call in base ad una delle
vtbl. Se la funzione chiamata si aspetta effettivamente il puntatore da cui e'
avvenuta la chiamata, l'indirizzo della vtbl contiene l'indirizzo della
funzione. Altrimenti contiene l'indirizzo di uno stub che converte il puntatore
come richiesto caso per caso e poi esegue un jump (siamo nel dominio
dell'assembler, ovviamente) alla funzione vera e propria.
--
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

 puntano a due vtbl diverse (ma ovviamente equivalenti).
quindi con l'upcast si può accedere a tuttoi e due i sub-oggetti ?
es.:
// B::foo()
D d;
((M1*)&d)->foo();
((M2*)&d)->foo();
è giusto?

 è giusto?
Si. Ma forse e' piu' comodo con:
d.M1::foo();
d.M2::foo();
