есть ли причина, по которой переопределение не может быть разрешено во время компиляции.
Предполагая, что вы говорите о полиморфизме, т.е.
#include <iostream>
class Base
{
public:
virtual void Foo()
{
std::cout << "Base::Foo()" << std::endl;
}
};
class Derived : public Base
{
public:
virtual void Foo()
{
std::cout << "Derived::Foo()" << std::endl;
}
};
Приведенный выше код позволяет примерно так работать, как ожидалось:
void CallFoo(Base& b)
{
b.Foo();
}
int main()
{
Base b;
Derived d;
CallFoo(b); // calls Base::Foo()
CallFoo(d); // Calls Derived::Foo();
}
Важно понимать, что CallFoo()
ничего не знает о том, что на самом деле b
(это может относиться к экземпляру Base
или Derived
). Все, что получает CallFoo()
- это ссылка на Base
, которая ничего не говорит о том, к чему он на самом деле относится, поэтому компилятор не может сказать, что это, когда компилирует CallFoo()
. Следовательно, определение того, следует ли вызывать Base::Foo()
или Derived::Foo()
, обязательно является решением времени выполнения.
Удаление ключевых слов virtual
(чтобы отключить переопределение) приведет к тому, что приведенный выше код будет печатать дважды Base::Foo()
, а не Base::Foo()
, а затем Derived::Foo()
. Это связано с тем, что без ключевого слова virtual
компилятор просто разрешит вызов Base::Foo()
во время компиляции.
При этом, поскольку виртуальные функции несут некоторые издержки (в конце концов, правильная функция, которую нужно вызвать, является решением времени выполнения), компиляторы постараются изо всех сил выяснить фактический тип b
в CallFoo()
если может. В этом случае это становится решением во время компиляции. Это, однако, деталь реализации.