No hay MRO en C++ como Python. Si un método es ambiguo, es un error en tiempo de compilación. Si un método es virtual o no, no lo afecta, pero la herencia virtual lo hará.
El algoritmo se describe en el C++ estándar § [class.member.lookup] (10.2). Básicamente, encontrará la implementación no ambigua más cercana en el gráfico de la superclase. El algoritmo funciona así:
Supongamos que desea buscar una función f en la clase C .
definimos un look-up estableceS (f, C) ser un par de conjuntos (Δ, Σ) que representa todas las posibilidades. (§ 10,2/3)
El conjunto Δ se llama la declaración establece, que es básicamente todas las posibles f 's.
El conjunto Σ se llama el subobjeto establece, que contienen las clases que se encuentre este f 's.
Vamos S (f, C) incluyen todos f directamente definido (o using
-ed) en C, si cualquier (§ 10.2/4):
Δ = {f in C};
if (Δ != empty)
Σ = {C};
else
Σ = empty;
S(f, C) = (Δ, Σ);
If S (F, C) está vacía (§ 10,2/5),
Compute S (f, B i) donde B i es una clase base de C, para todos i.
Combinar cada S (f, B i) en S (F, C) uno por 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);
}
Finalmente el conjunto declaración se obtiene como resultado de la resolución de nombres (§ 10.2/7).
return S(f, C).Δ;
La fusión entre dos conjuntos de consulta (Δ, Σ) y (Δ, Σ) se define como (§ 10.2/6):
- Si cada clase en Σ es una clase base de al menos una clase en Σ, de retorno (Δ, Σ)
(similares a la inversa.)
- Porque si Δ ≠ Δ, de retorno ( ambigua, Σ ∪ Σ).
De lo contrario, de retorno (Δ, Σ ∪ Σ)
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 (Δ, Σ);
}
}
Por ejemplo (§ 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();
}
};
calculamos que
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.
y
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.
Chicos, él no está preguntando acerca de una tabla virtual. Él pregunta cómo el compilador elige a qué 'foo' se llama. – GManNickG