Pregunta

Considerar la jerarquía de clase siguiente:

  • objeto de clase base con un método virtual foo ()
  • una jerarquía arbitraria con múltiples herencias (virtuales y no virtuales);Cada clase es un subtipo de objeto;Algunos de ellos anulan foo (), algunos no
  • una clase x de esta jerarquía, no anulando foo ()

¿Cómo determinar qué método se ejecutará en una llamada de FOO () en un objeto de clase X en C ++?

(Estoy buscando el algoritmo, no ningún caso específico).

¿Fue útil?

Solución

No hay MRO en C ++ como Python. Si un método es ambiguo, es un error de tiempo de compilación. Si un método es virtual o no, no lo afecta, sino la herencia virtual .


El algoritmo se describe en el estándar C ++ § [Class.member.lookup] (10.2). Básicamente, encontrará la implementación no ambigua más cercana en el gráfico de SuperClass. El algoritmo funciona así:

  1. Suponga que desea buscar una función f en la clase c .

  2. Definimos un conjunto de búsqueda s (f, c) siendo un par de conjuntos ( δ , Σ ) que representa todas las posibilidades. (§10.2 / 3)

    • El conjunto δ se llama el conjunto de declaración , que es básicamente todo lo posible f 's.

    • El conjunto σ se llama el conjunto de subobject , que contiene las clases que se encuentran estos f '.

  3. Sean s (f, c) incluyen todos f directamente definido (o using-ed) en c , si es (§10.2 / 4) :

    Δ = {f in C};
    if (Δ != empty)
      Σ = {C};
    else
      Σ = empty;
    S(f, C) = (Δ, Σ);
    
  4. Si s (f, c) está vacío (§10.2 / 5) ,

    • calcular s (F, b i ) donde b i es una clase base de c , para todos i .

    • fusiona 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);
      }
      
  5. Finalmente, el conjunto de declaración se devuelve como resultado de la resolución de nombres (§10.2 / 7) .

    return S(f, C).Δ;
    
  6. La fusión entre dos juegos de búsqueda ( δ 1 , σ 1 ) y ( δ 2 , σ 2 ) se define como (§10.2 / 6) :

    • Si cada clase en σ 1 es una clase base de al menos una clase en σ 2 , retorno ( Δ 2 , σ 2 ).
      (Similar para el reverso.)
    • si Δ 1 δ 2 , devuelva ( ambiguo , σ 1 σ 2 ).
    • de lo contrario, retorno ( δ 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 (Δ, Σ);
         }
      }
      

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

    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.
    

Otros consejos

Alguna descripción detallada con código.

vable yvptr

vtable

Funciones virtuales

Si está hablando de G++, se usa una tabla de métodos virtuales ), puede obtener más detalles específicos aquí .No estoy seguro de si cada compilador C ++ usa el mismo enfoque, pero diría que sí

Si un método de una clase base es virtual, cada llamada a él a través de la base o el puntero / referencia derivado llamará al método apropiado (el uno más le más abajo hacia abajo del árbol heredal).Si el método fue declarado virtual, no puede tenerlo de ninguna otra manera más adelante: declararlo, las clases derivadas (o no), virtuales, no cambiarán nada.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top