Método de resolução ordem em C++
Pergunta
Considere a seguinte hierarquia de classes:
- Objeto de classe base virtual, o método foo()
- um arbitrário hierarquia com herança múltipla (virtuais e não-virtuais);cada classe é um subtipo do Objeto;alguns deles substituir foo(), alguns não
- uma classe X a partir desta hierarquia, não substituindo foo()
Como determinar qual método será executado após uma chamada de foo() em um objeto da classe X em C++?
(Eu estou olhando para o algoritmo, não qualquer caso específico.)
Solução
Não há MRO em C++, como Python.Se um método é ambíguo, é um erro em tempo de compilação.Se um método é virtual ou não, não o afeta, mas virtual herança vontade.
O algoritmo é descrito no padrão de C++ §[classe.- membro.de pesquisa] (10.2).Basicamente, ele vai encontrar o mais próximo inequívoca implementação da superclasse gráfico.O algoritmo funciona da seguinte forma:
Suponha que você deseja procurar uma função f na classe de C.
Podemos definir look-up definido S(f, C) sendo um par de conjuntos (Δ, Σ), o que representa todas as possibilidades. (§10.2/3)
O conjunto de Δ é chamado o declaração, que é basicamente tudo o possível f's.
O conjunto de Σ é chamado o conjunto de subobjectos, que contém as classes que estes f's são encontrados.
Deixe S(f, C) incluir todos os f definidas diretamente (ou
using
-ed) em C, se qualquer (§10.2/4):Δ = {f in C}; if (Δ != empty) Σ = {C}; else Σ = empty; S(f, C) = (Δ, Σ);
Se S(f, C) está vazia (§10.2/5),
Computação S(f, Beu) onde Beu é uma classe base de C, para todos os eu.
Mesclar cada S(f, Beu) em S(f, C) um por um.
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, a declaração é retornado como resultado da resolução de nomes (§10.2/7).
return S(f, C).Δ;
A mesclagem entre o olhar de dois conjuntos (Δ1, Σ1 eΔ2, Σ2) é definido como (§10.2/6):
- Se cada classe Σ1 é uma classe base de, pelo menos, uma classe no Σ2, retorno (Δ2, Σ2).
(Semelhante para o inverso.) - Outra coisa se Δ1 ≠ Δ2, retorno (ambíguo, Σ1 ∪ Σ2).
Caso contrário, retornar (Δ1, Σ1 ∪ Σ2)
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 (Δ, Σ); } }
- Se cada classe Σ1 é uma classe base de, pelo menos, uma classe no Σ2, retorno (Δ2, Σ2).
Por exemplo (§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.
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.
Outras dicas
Se você está falando sobre G++
uma vtable (Tabela De Método Virtual) é usado, você pode obter detalhes mais específicos aqui.Não tenho certeza se todos os compilador C++ usa a mesma abordagem, mas eu diria que sim
Se um método de uma classe base for virtual, todas as chamadas para ele por meio de base ou referência derivada receberão o método apropriado (o mais distante da árvore de herança).Se o método foi declarado virtual, você não pode ter qualquer outra maneira mais tarde: declarando virtual (ou não) em classes derivadas não alterará nada.