Question

Considérez la hiérarchie de classe suivante:

  • objet de la classe de base avec une méthode virtuelle FOO ()
  • une hiérarchie arbitraire à héritage multiple (virtuel et non virtuel);Chaque classe est un sous-type d'objet;certains d'entre eux remplacent foo (), certains ne
  • Une classe X de cette hiérarchie, ne pas remplacer foo ()

Comment déterminer quelle méthode sera exécutée sur un appel de FOO () sur un objet de classe X en C ++?

(Je cherche l'algorithme, pas un cas particulier.)

Était-ce utile?

La solution

Il n'y a pas de MRO en C ++ comme Python. Si une méthode est ambiguë, c'est une erreur de compilation. Si une méthode est virtuelle ou non ne l'affecte pas, mais virtuel héritage sera.


L'algorithme est décrit dans la norme C ++ § [Class.Member.Lookup] (10.2). Fondamentalement, il trouvera la mise en œuvre sans ambiguïté la plus proche du graphique de la superclasse. L'algorithme fonctionne comme ceci:

  1. supposons que vous voulez rechercher une fonction f en classe C .

  2. Nous définissons un ensemble look-up s (f, c) étant une paire d'ensembles ( δ "fort > Σ ) représentant toutes les possibilités. (§10.2 / 3)

    • L'ensemble δ est appelé le jeu de déclaration , qui est fondamentalement tout le possible f .

    • L'ensemble σ est appelé le jeu sous-box , qui contiennent les classes que ces f sont trouvés.

  3. laisse s (f, c) inclure tous les F directement définis (ou généracodetagcode-éd) dans C , le cas échéant (§10.2 / 4) :

    Δ = {f in C};
    if (Δ != empty)
      Σ = {C};
    else
      Σ = empty;
    S(f, C) = (Δ, Σ);
    
  4. si s (f, c) est vide (§10.2 / 5) ,

    • calcule s (f, b i ) b i est une classe de base de C , pour tous i .

    • fusionner chaque s (f, b i ) dans s (f, c) un par un.

      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. Enfin, l'ensemble de déclaration est renvoyé à la suite de la résolution de noms (§10.2 / 7) .

    .
    return S(f, C).Δ;
    
  6. la fusion entre deux ensembles de recherche ( δ 1 , σ 1 ) et ( δ 2 , σ 2 ) est défini comme (§10.2 / 6) :

    • Si chaque classe in σ 1 est une classe de base d'au moins une classe dans σ 2 , Retour ( δ 2 , σ 2 ).
      (Semblable pour l'inverse.)
    • sinon si δ 1 δ 2 , retour ( ambigu de , 1 σ 2 ).
    • sinon, renvoyez ( δ 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. Par exemple (§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();
       }
    };
    

    Nous calculons 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.
    

    et

    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.
    

Autres conseils

Une description détaillée avec code.

Table /VPTR

VTable

Fonctions virtuelles

Si vous parlez de G++, une table à fourchette ( la table de la méthode virtuelle ) est utilisée, vous pouvez obtenir plus de détails spécifiques ici .Je ne sais pas si chaque compilateur C ++ utilise la même approche, mais je dirais oui

Si une méthode d'une classe de base est virtuelle, chaque appel à celui-ci à travers la base ou le pointeur dérivé / référence appellera la méthode appropriée (la fois la plus éloignée de l'arborescence d'héritage).Si la méthode a été déclarée virtuelle, vous ne pouvez pas l'avoir autrefois: la déclarant virtuelle (ou non) dans des classes dérivées ne changera rien.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top