Ho un risultato che non mi aspettavo dall'ereditarietà multipla, i metodi virtual
e i puntatori alle classi di base.Eredità multipla, collisione dei metodi virtuali e puntatori delle classi base
Con d.getStr()
, quando d
è un'istanza derived
, la versione base_2
si chiama, come mi aspettavo.
Con p->getStr()
, quando p
è un puntatore a un'istanza derived
(o un puntatore a base_2
che punta a un'istanza derived
), la versione base_2
è chiamato, come mi aspettavo.
Ma con p->getStr()
, quando p
è un puntatore ad una base_1
che punta a un'istanza derived
, la versione base_1
è chiamato ed ero convinto sarebbe chiamato la versione base_2
(grazie alla using
e il fatto che getStr()
sono virtual
metodi) .
Il seguente è un semplice esempio:
#include <iostream>
struct base_1
{
virtual std::string getStr() const
{ return "string from base 1"; }
};
struct base_2
{
virtual std::string getStr() const
{ return "string from base 2"; }
};
struct derived : public base_1, public base_2
{
using base_2::getStr;
};
int main()
{
derived d;
derived * dp = &d;
base_1 * bp1 = &d;
base_2 * bp2 = &d;
std::cout << "from derived: " << d.getStr() << std::endl;
std::cout << "from derived pointer: " << dp->getStr() << std::endl;
std::cout << "from base_1 pointer: " << bp1->getStr() << std::endl;
std::cout << "from base_2 pointer: " << bp2->getStr() << std::endl;
}
L'uscita è il seguente
from derived: string from base 2
from derived pointer: string from base 2
from base_1 pointer: string from base 1
from base_2 pointer: string from base 2
so che, di imporre la chiamata di base_2
versione, posso aggiungere nel derived
il metodo seguente
std::string getStr() const
{ return base_2::getStr(); }
ma le mie domande sono:
1) Perché il puntatore a base_1
(che punta a un'istanza derivata) ignora la direttiva using
e chiama la versione base_1
di getStr()
?
2) Esiste un modo per imporre la versione base_2
di getStr()
, quando derived
esempio viene utilizzato da un puntatore base_1
, senza ridefinire getStr()
?
--- EDIT ---
Grazie per le risposte.
Capisco che stai descrivendo cosa sta succedendo ma il mio dubbio è: la lingua (lo standard) descrive questo aspetto? O è una parte indefinita?
voglio dire: se mi tolgo la direttiva using
, ottengo un errore di compilazione (error: request for member getStr is ambiguous
), da d.getStr()
e da dp->getStr()
, perché il compilatore non sa quale versione di getStr()
di scegliere.
Ma getStr()
sono i metodi virtual
. Quindi (ero convinto che) un puntatore di base dovrebbe usare la versione derivata di loro. Ma abbiamo un paio di metodi di collisione.
Dal punto di vista della lingua (standard), uno base_1
(o base_2
) è il puntatore autorizzato (o obbligato) a scegliere una delle due versioni dei metodi collidenti che ignorano l'altro?
Forse mi sbaglio ma mi sembra che, in questo modo, i metodi virtual
siano gestiti come metodi non virtual
.
"using" aiuta solo in visibilità. Non rende "sovraccaricato" la funzione virtuale di base o ne assomiglia. – Arunmu