Non c'è MRO in C++ come Python. Se un metodo è ambiguo, si tratta di un errore in fase di compilazione. Se un metodo è virtuale o meno non lo influenza, ma l'ereditarietà virtuale sarà.
L'algoritmo è descritto nella C++ norma § [class.member.lookup] (10.2). Fondamentalmente troverà l'implementazione non ambigua più vicina nel grafico della superclasse. L'algoritmo funziona così:
Si supponga di voler ricercare una funzione f in classe C .
definiamo un look-up impostatoS (f, C) essendo una coppia di gruppi (Δ, Σ) rappresenta tutte le possibilità. (§ 10,2/3)
Il set Δ è chiamato dichiarazione impostato, che è sostanzialmente tutti i possibili f 's.
Il set Σ è chiamato subobject impostato, che contengono le classi che questi f 's si trovano.
Let S (f, C) comprendono tutti f direttamente definito (o using
-ed) in C eventuali (§ 10.2/4):
Δ = {f in C};
if (Δ != empty)
Σ = {C};
else
Σ = empty;
S(f, C) = (Δ, Σ);
If S (f, C) è vuota (§ 10,2/5),
Calcola S (f, B i) dove B i è una classe base di C, per tutti i.
unione ciascuno S (f, B i) in S (f, C) uno per uno.
if (S(f, C) == (empty, empty)) {
B = base classes of C;
for (Bi in B)
S(f, C) = S(f, C) .Merge. S(f, Bi);
}
Infine il set dichiarazione viene restituito come risultato della risoluzione dei nomi (§ 10,2/7).
return S(f, C).Δ;
L'unione tra due insiemi di look-up (Δ, Σ) e (Δ, Σ) è definito come (§ 10,2/6):
- Se ogni classe Σ è una classe base di almeno una classe in Σ, ritorno (Δ, Σ).
(simili per la retromarcia.)
- Altrimenti se Δ ≠ Δ, ritorno (ambiguo, Σ ∪ Σ).
Altrimenti, ritorno (Δ, Σ ∪ Σ)
function Merge ((Δ1, Σ1), (Δ2, Σ2)) {
function IsBaseOf(Σp, Σq) {
for (B1 in Σp) {
if (not any(B1 is base of C for (C in Σq)))
return false;
}
return true;
}
if (Σ1 .IsBaseOf. Σ2) return (Δ2, Σ2);
else if (Σ2 .IsBaseOf. Σ1) return (Δ1, Σ1);
else {
Σ = Σ1 union Σ2;
if (Δ1 != Δ2)
Δ = ambiguous;
else
Δ = Δ1;
return (Δ, Σ);
}
}
Per esempio (§ 10,2/10),
struct V { int f(); };
struct W { int g(); };
struct B : W, virtual V { int f(); int g(); };
struct C : W, virtual V { };
struct D : B, C {
void glorp() {
f();
g();
}
};
calcoliamo che
S(f, D) = S(f, B from D) .Merge. S(f, C from D)
= ({B::f}, {B from D}) .Merge. S(f, W from C from D) .Merge. S(f, V)
= ({B::f}, {B from D}) .Merge. empty .Merge. ({V::f}, {V})
= ({B::f}, {B from D}) // fine, V is a base class of B.
e
S(g, D) = S(g, B from D) .Merge. S(g, C from D)
= ({B::g}, {B from D}) .Merge. S(g, W from C from D) .Merge. S(g, V)
= ({B::g}, {B from D}) .Merge. ({W::g}, {W from C from D}) .Merge. empty
= (ambiguous, {B from D, W from C from D}) // the W from C is unrelated to B.
Ragazzi, non sta chiedendo di un tavolo virtuale. Sta chiedendo come il compilatore sceglie quale 'foo' è chiamato. – GManNickG