我想知道动态调度在 C++ 中是如何工作的。为了说明我的问题,我将从一些 Java 代码开始。
class A
{
public void op(int x, double y) { System.out.println("a"); }
public void op(double x, double y) { System.out.println("b"); }
}
class B extends A
{
public void op(int x, double y) { System.out.println("c"); }
public void op(int x, int y) { System.out.println("d"); }
}
class C extends B
{
public void op(int x, int y) { System.out.println("e"); }
}
public class Pol
{
public static void main(String[] args)
{
A a = new C();
B b = new C();
/* 1 */ a.op(2, 4);
/* 2 */ b.op(2.0, 4.0);
}
}
该调用a.op(2, 4)
将打印“c”,因为确实是编译器:
- 查看 Class
A
(因为a
被声明为类型的变量A
)哪个方法最接近op(int, int)
, - 找不到
op(int, int)
方法但找到了方法op(int, double)
(使用单个自动转换int
->double
), - 然后修复此签名。
在执行期间,JVM:
op(int, double)
在 Class 中寻找具有编译器固定签名的方法,C
但没有找到,- 查看 C 的超类内部,即
B
, - 最后找到一个方法
op(int, double)
,然后调用它。
同样的原则也适用于b.op(2.0, 4.0)
打印“b”的调用。
现在,考虑 C++ 中的等效代码
#include <iostream>
class A
{
public:
virtual void op(int x, double y) { std::cout << "a" << std::endl; }
virtual void op(double x, double y) { std::cout << "b" << std::endl; }
};
class B : public A
{
public:
void op(int x, double y) { std::cout << "c" << std::endl; }
virtual void op(int x, int y) { std::cout << "d" << std::endl; }
};
class C : public B
{
public:
void op(int x, int y) { std::cout << "e" << std::endl; }
};
int main()
{
A *a = new C;
B *b = new C;
/* 1 */ a->op(2, 4);
/* 2 */ b->op(2.0, 4.0);
delete a;
delete b;
}
a->op(2, 4)
将打印“c”,如 Java。但是b->op(2.0, 4.0)
再次输出“c”,我迷路了。
在编译和在 C++ 中执行期间用于动态调度的规则到底是什么?(请注意,如果您virtual
在每个函数前面编写代码,C++ 代码将具有相同的行为;这里没有任何改变)