C ++中的方法解析顺序 [英] Method resolution order in 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:
-
假设您要在类 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屋!