C ++中的方法解析顺序 [英] Method resolution order in C++

查看:76
本文介绍了C ++中的方法解析顺序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下类层次结构:

Consider the following class hierarchy:

  • 带有虚拟方法foo()的基类对象
  • 具有多重继承(虚拟和非虚拟)的任意层次结构;每个类都是Object的子类型;其中有些覆盖foo(),有些则不覆盖
  • 该层次结构中的X类,不覆盖foo()

如何确定在C ++中对类X的对象调用foo()时将执行哪种方法?

How to determine which method will be executed upon a call of foo() on an object of class X in C++?

(我正在寻找算法,而不是任何特定情况.)

(I'm looking for the algorithm, not any specific case.)

推荐答案

在C ++中,没有像Python这样的MRO.如果方法不明确,则是编译时错误.方法是否是虚拟的都不会影响它,但是虚拟的继承会影响.

There is no MRO in C++ like Python. If a method is ambiguous, it is a compile-time error. Whether a method is virtual or not doesn't affect it, but virtual inheritance will.

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

The algorithm is described in the C++ standard §[class.member.lookup] (10.2). Basically it will find the closest unambiguous implementation in the superclass graph. The algorithm works like this:

  1. 假设您要在类 C 中查找函数 f .

我们定义一个查找集 S(f,C)是一对集(Δ Σ )代表所有可能性. (§ 10.2/3)

We define a look-up set S(f, C) being a pair of sets (Δ, Σ) representing all possibilities. (§10.2/3)

  • 集合Δ 被称为声明集合,基本上是所有 f 的可能.

  • The set Δ is called the declaration set, which is basically all the possible f's.

集合Σ 被称为子对象集合,其中包含找到这些 f 的类. /p>

The set Σ is called the subobject set, which contain the classes that these f's are found.

S(f,C)包括在 C 中直接定义(或using -ed)的所有 f ,如果有(§ 10.2/4):

Let S(f, C) include all f directly defined (or using-ed) in C, if any (§10.2/4):

Δ = {f in C};
if (Δ != empty)
  Σ = {C};
else
  Σ = empty;
S(f, C) = (Δ, Σ);

  • 如果 S(f,C)为空(§ 10.2/5)

    • 计算 S(f,B i ),其中 B i C ,用于所有 i .

    将每个 S(f,B i )逐一合并到 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);
    }
    

  • 最后,声明集将作为名称解析(§ 10.2/7)的结果而返回.

    Finally the declaration set is returned as the result of name resolution (§10.2/7).

    return S(f, C).Δ;
    

  • 两个查询集(Δ 1 Σ 1 )和(Δ 2 Σ 2 )被定义为(§ 10.2/6):

  • The merge between two look-up sets (Δ1, Σ1) and (Δ2, Σ2) is defined as (§10.2/6):

    • 如果Σ 1 中的每个类都是Σ 2 中至少一个类的基类,返回(Δ 2 Σ 2 ).
      (与之相反).
    • 否则,如果Δ 1 Δ 2 ,则返回(模糊Σ 1 Σ 2 ).
    • 否则,返回(Δ 1 Σ 1 Σ 2 )

    • If every class in Σ1 is a base class of at least one class in Σ2, return (Δ2, Σ2).
      (Similar for the reverse.)
    • Else if Δ1Δ2, return (ambiguous, Σ1Σ2).
    • Otherwise, return (Δ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.
    

    这篇关于C ++中的方法解析顺序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆