Интересно, как динамическая диспетчеризация действительно работает на С++. Чтобы проиллюстрировать мой вопрос, я начну с кода 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 перед каждой функцией, здесь ничего не меняется)