代码之家  ›  专栏  ›  技术社区  ›  Kos

C++中的方法解析顺序

  •  10
  • Kos  · 技术社区  · 14 年前

    考虑以下类层次结构:

    • 具有多重继承(虚拟和非虚拟)的任意层次结构;每个类都是对象的子类型;有些重写foo(),有些则不重写
    • 此层次结构中的类X,不重写foo()

    如何确定在C++类中的对象上调用FoE()时执行的方法?

    4 回复  |  直到 14 年前
        1
  •  29
  •   kennytm    14 年前

    在C++中没有像Python那样的MRO。如果方法不明确,则是编译时错误。一个方法是否是虚拟的并不影响它,而是虚拟的 继承


    在C++标准中描述了该算法。§[class.member.lookup](10.2)。基本上,它将在超类图中找到最接近的明确实现。算法的工作原理如下:

    1. 假设你想查一个函数 在课堂上 C级

    2. 查找集 成为一对( Δ , Σ )代表所有的可能性。 (§10.2/3)

      • 那套 Δ 被称为 ,这基本上是所有可能的 f

      • 那套 Σ 子对象集 ,其中包含这些 f 找到的。

    3. S(f,C) 包括所有 f using -ed)英寸 C级 ,如果有的话 (§10.2/4)

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

      • 计算 S(f,B) ) 哪里 B类 是的基类 .

      • 合并每个 ) 进入之内 S(f,C)

        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. 最后,作为名称解析的结果返回声明集 .

      return S(f, C).Δ;
      
    6. 两个查找集之间的合并( Δ 1 , Σ 1 Δ 2 Σ 2 (§10.2/6) :

      • 如果每个班级 1 是中至少一个类的基类 ,返回( 2 , 2 ).
        (反面类似。)
      • 否则如果 1 模棱两可的 1 2 ).
      • 否则,返回( 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 (Δ, Σ);
           }
        }
        

    (§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();
       }
    };
    

    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.
    

    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.
    
        3
  •  0
  •   Jack    14 年前

    如果你说的是 G++ 虚拟方法表 here . 不确定每个C++编译器是否使用相同的方法,但我会说是的

        4
  •  0
  •   fingerprint211b    14 年前