Согласно Википедии, Многократная отправка когда
… функция или метод могут отправляться динамически в зависимости от типа времени выполнения (динамического) нескольких аргументов.
Однако в C ++ я могу переопределить функцию в производном классе:
#include <iostream>
using namespace std;
class Base
{
public:
virtual void method(int a) { cout << a; }
virtual void method(int a, int b) { cout << a + b; }
};
class Derived: public Base
{
void method(int a) { cout << a * 10 << endl; }
void method(int a, int b) { cout << (a + b) * 10 <<endl; }
};
int main()
{
Base* derived = new Derived;
derived->method(1);
derived->method(1, 2);
return 0;
}
Здесь method
привязан во время выполнения (потому что я использую virtual
) и конкретный метод выбирается на основе входных параметров. Чем он отличается от описания множественной отправки в Википедии?
Вторичный вопрос: В чем преимущество (если есть) языков, которые поддерживают множественную диспетчеризацию, если такая комбинация полиморфизма и перегрузки методов существует в C ++?
Нет. Кандидат выбирается статически компилятором на основе статических типов получателя и аргументов. Затем во время выполнения используется только динамический тип получателя, чтобы связать вызов с наиболее конкретным переопределяющим методом. Динамические типы аргументов не играют никакой роли на этапе динамического связывания.
В вашем конкретном случае это означает, что для вызова derived->method(1);
компилятор смотрит на статические типы получателя (Base
) и фактических аргументов (int
). Затем он ищет среди всех методов Base
(наследуется или объявляется в Base
) для того, который подходит лучше всего; это Base::method(int)
, Во время выполнения система времени выполнения смотрит на динамический тип получателя (Derived
) для наиболее конкретного метода, который переопределяет Base::method(int)
, который Derived::method(int)
и вызывает этот метод с заданным фактическим аргументом (1
).
Аналогично для второго звонка.
Он связывается во время выполнения в соответствии только с одним аргументом, объектом, к которому он вызывается. Виртуальные функции обеспечивают не замужем диспетчеризация в соответствии с (динамическим) типом объекта, к которому они обращаются.
Выбор перегрузки на основе количества и (статического) типа других аргументов выполняется во время компиляции.
Это не множественная диспетчеризация, поскольку выбор во время выполнения выполняется только на основе одного параметра: типа объекта «производный». Разрешение перегрузки функции обрабатывается во время компиляции.
virtual void Base::method(int a);
можно рассматривать как
/*virtual*/ void method(Base&, int a);
Итак, в вашем случае у вас есть
derived->method(1);
будет отправлять между:
/*virtual*/ void method(Base&, int a);
/*virtual*/ void method(Derived&, int a);
А также derived->method(1, 2);
будет отправлять между:
/*virtual*/ void method(Base&, int a, int b);
/*virtual*/ void method(Derived&, int a, int b);
И в обоих случаях отправляется только по одному аргументу.
С
void method2(Base&, Base&);
void method2(Derived&, Base&);
void method2(Base&, Derived&);
void method2(Derived&, Derived&);
Если вы этого хотели (с Base* derived = new Derived
)
method2(*derived, *derived);
звонки void method2(Derived&, Derived&);
тогда это требует многократной отправки.
(В настоящее время он называет void method2(Base&, Base&);
).