Тип привязки для не переопределенной виртуальной функции - PullRequest
1 голос
/ 25 января 2012

Рассмотрим случай, когда virtual function в базовом классе равно not overriden в производном классе.Затем с помощью base class pointer to a derived class object вызывается виртуальная функция.

Я понимаю, что вызов функции будет разрешен для функции в базовом классе во время компиляции.

Вопрос

Поскольку функция не переопределяется в производном классе, вызов функции будет связан с реализацией функции во время компиляции или все равно будет задерживатьпривязка до времени выполнения?

Ответы [ 2 ]

1 голос
/ 25 января 2012

Чтобы иметь возможность угадать реализацию во время компиляции, компилятор должен знать тип указанного объекта ... например

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, и он может быть равен адресу базовой реализации или не зависеть от того, была ли функция переопределена в производном классе.

1 голос
/ 25 января 2012

Скорее всего, это будет решено во время компиляции.
Большинство современных дневных компиляторов достаточно умны, чтобы разрешить динамическую диспетчеризацию во время компиляции, если для этого достаточно надежной информации.
В этом случае, поскольку в классе Derived не предусмотрена переопределяющая функция, умный компилятор должен иметь возможность статически разрешать вызов функции во время компиляции.

...