Как перегрузка и переопределение работают вместе?

Я понимаю основы перегрузки и переопределения, но что-то меня смущает. Я попытаюсь объяснить, используя простой пример:

  • Класс B имеет функцию X (B& б)
  • Класс D наследуется от класса B.
  • Класс D переопределяет X с помощью X (B& б), а также перегружает его X (D& г).

У меня тогда есть следующий код:

void test(D& d1, B& b1, D& d2, B& b2){
d1.X(d2);
d1.X(b2);
b1.X(d2);
b1.X(b2);
}

int main(){
D d1, d2, d3, d4;
test(d1, d2, d3, d4);
}

Я очень не уверен, как третьи и четыре строки test() будет определять, какие реализации X () вызывать и каковы общие механизмы, которые происходят.

1

Решение

Есть два шага: выбор перегрузки (X(B&) против X(D&)) и, как только это будет сделано, найти правильную реализацию выбранной функции. Первое происходит во время компиляции и зависит от статические типы объекта а также его аргументы, последний происходит во время выполнения и зависит от динамический тип объекта (обратите внимание, что это делает не зависит от динамического типа аргументов).

Четыре объекта объявлены следующим образом: d1 а также d2 являются D&так их статический тип является D&, а также b1 а также b2 объявлены как B&поэтому их статический тип B&, Статический тип — это то, что вы объявили в коде.

Но динамический тип для всех четырех D, потому что все четыре ссылки на самом деле ссылаются на объекты, которые вы создали как D-объекты в main(),

Поэтому первый шаг, выбор перегрузки: в случае b1.X(b2) а также b1.X(d2)есть только одна возможная перегрузка, X(B&)потому что статический тип B&и определение класса для B имеет только эту функцию. Но в случае d1.X(b2) а также d1.X(d2)выбор перегрузки основан на определении класса Dпотому что статический тип D&, Итак, рассматриваются две перегрузки: X(B&) а также X(D&), Когда аргумент b2, первая перегрузка выбрана, и когда аргумент d2выбрана последняя перегрузка — все основано на статических (= объявленных) типах объектов и аргументов.

Второй шаг, выбор правильной реализации выбранной перегрузки. Это происходит во время выполнения и зависит от динамического типа объекта (не аргументов). Так что в случае b1.X(b2), потому что динамический тип b1 является D, это в конечном итоге вызов D::X(B&), То же самое для b1.X(d2): Перегрузка, выбранная на предыдущем шаге, была X(B&), но выбранная реализация D::X(B&), (D::X(D&) на данный момент не подходит, потому что это будет другая перегрузка, и перегрузка уже выбрана на основе статического типа). В случае d1.X(b2) а также d1.X(d2), выбранные функции такие же, как на первом этапе, D::X(B&) а также D::X(D&)потому что динамический тип объекта совпадает со статическим типом.

1

Другие решения

Вы объявляете виртуальную функцию X в B(B::X)и переопределить X в производном классе D(D::X), Если список параметров B::X а также D::X разные, B::X а также D::X считаются разными, D::X не переопределяет B::X, а также D::X не является виртуальным (если вы не объявили его с помощью ключевого слова virtual). Вместо, D::X шкуры B::X,

#include <iostream>
using namespace std;

struct B {
virtual void X() { cout << "Class B" << endl; }
};

struct D: B {
void X(int) { cout << "Class D" << endl; }
};

int main() {
D d;
B* pb = &d;
//   d.X();
pb->X();
}

Вы даже не можете позвонить d.X()скрыт D::X(int), Но pb->X() Это хорошо.

Итак, в вашем случае:

struct B {
virtual void X(B& b) { cout << "Class B" << endl; }
};

struct D: B {
void X(B& b) { cout << "Class D" << endl; }
void X(D& d) { cout << "Class D" << endl; }
};

D::X скроет B::X, Так d1.X(d2) а также d1.X(b2) в test() не имеет ничего общего с B::X, А также b1.X(d2), а также b1.X(b2) в test() позвоню D::X, Хотя B::X невидим в D, но D::X(B&) является виртуальным, независимо от того, объявляете ли вы D::X(B&) с виртуальным ключевым словом. Компилятор знает, что это виртуальная функция, поэтому D::X(B&) вызывается.

РЕДАКТИРОВАТЬ: Дополнительные пояснения к b1.X (b2), B :: X — это виртуальная функция, и D :: X переопределяет ее, поэтому определенно она будет вызывать D :: X посредством динамического связывания. А перегрузка определяется во время компиляции, поэтому она не будет вызывать D :: X (D&).

2

По вопросам рекламы [email protected]