Чтобы иметь возможность угадать реализацию во время компиляции, компилятор должен знать тип указанного объекта ... например
MyBaseClass *p = new MyDerivedClass;
p->foo();
В приведенном выше примере компилятор должен быть достаточно умным, чтобы угадать тип объекта, на который указывает указатель, и диспетчеризация (при условии, что компилятор использует решение VMT для позднего связывания) не должна требовать поиска VMT даже если метод виртуальный.
Однако, например, в следующем
void doit(MyBaseClass *p)
{
p->foo();
...
}
код для doit
не может знать тип объекта, на который указывает, и поэтому вызов потребует поиска VMT. Обратите внимание, что язык C ++ был разработан таким образом, чтобы компиляторы могли работать по одному модулю компиляции за раз, поэтому компилятор не может знать, что в вашей программе, например, только один производный тип (исходный код другого модуля может определять другой производный класс, даже в локальном безымянном пространстве имен, где функция переопределена).
Конечно, функция doit
может в конечном итоге быть встроенной компилятором, поэтому конкретный сайт вызова , вызывающий doit
, действительно может не требовать поиска, если тип может быть случайны. Но если функция doit
является публично видимой (например, она не находится в безымянном пространстве имен или статической свободной функции), то генерируемый для нее машинный код будет включать поиск VMT при вызове из других модулей компиляции.
Обратите внимание, что во всех этих обсуждениях вопрос о том, нужен или нет поиск, совершенно не имеет значения, была ли виртуальная функция переопределена или нет. Причина в том, что если виртуальная функция не была переопределена и диспетчеризация реализована с помощью VMT, то просто в производном классе VMT будет иметь в этом слоте адрес базовой реализации.
Другими словами, p->foo()
компилируется как
p->__VMT__[__FOO_VMT_SLOT_NUMBER__](p); // Dynamic dispatch
или
__DERIVED_FOO_IMPLEMENTATION__(p); // Type known at compile time
где __DERIVED_FOO_IMPLEMENTATION__
- указатель функции, сохраненный в VMT, и он может быть равен адресу базовой реализации или не зависеть от того, была ли функция переопределена в производном классе.