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.)

Foi útil?

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:

  1. Suponha que você deseja procurar uma função f na classe de C.

  2. 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.

  3. 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) = (Δ, Σ);
    
  4. 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);
      }
      
  5. Finalmente, a declaração é retornado como resultado da resolução de nomes (§10.2/7).

    return S(f, C).Δ;
    
  6. 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 (Δ, Σ);
         }
      }
      

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

Alguma descrição detalhada com código.

VTable evptr

VTable

funções virtuais

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top