Во-первых, пример для иллюстрации.
struct B {
virtual B* f() { return this; }
};
struct D : B {
D* f() override { return this; }
};
void bar(B*) {}
void bar(D*) {}
int main() {
D d;
B& b = d;
bar(b.f()); // calls `bar(B*)`
}
Здесь постфиксное выражение b.f
обозначает функцию.Это B::f
, а его тип возврата - B*
.Хотя при переопределении f
указанный тип возвращаемого значения является ковариантным (D*
).Тот факт, что реальный вызов (предположительно) разрешен во время выполнения, не меняет того факта, что мы статически выбираем идентификатор функции .Это уместно, когда также происходит перегрузка.Одно и то же имя функции может обозначать две или более функций, и это разрешение перегрузки, которое (статически) выбирает, какую перегрузку вызывать.Эта перегрузка может быть переопределена в производном классе, но опять-таки его идентичность является статической.