Интересно, как динамическая диспетчеризация действительно работает на С++. Чтобы проиллюстрировать мой вопрос, я начну с кода 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" , так как действительно компилятор:
- смотрит в класс
A
(так какA
объявляется переменной типаA
), какой метод близок кop(int, int)
, - не может найти метод
op(int, int)
, но находит методop(int, double)
(с одним авто-литьемint
→double
), - затем фиксирует эту подпись.
Во время выполнения JVM:
- ищет метод с сигнатурой
op(int, double)
, установленный компилятором в классC
, но не находит его, - просматривает C суперкласс, т.е.
B
, - и, наконец, находит метод
op(int, double)
, затем вызывает его.
Тот же принцип применяется к вызову b.op(2.0, 4.0)
, который печатает "b".
Теперь рассмотрим эквивалентный код в С++
#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" снова, и там, я потерян.
Каковы правила, применяемые при компиляции и во время выполнения на С++ для динамической диспетчеризации?
(Обратите внимание, что у вас будет такое же поведение с кодом С++, если вы пишете virtual
перед каждой функцией, здесь ничего не меняется)