Встроенная виртуальная функция
В С++ я понимаю, что виртуальная функция может быть встроена, но, как правило, намек на inline игнорируется. Кажется, что встроенные виртуальные функции не имеют особого смысла.
Правильно ли это?
Может ли кто-нибудь дать случай, когда встроенная виртуальная функция хороша?
Ответы
Ответ 1
При нормальных обстоятельствах виртуальная функция будет вызываться через указатель на функцию (содержащуюся в классе 'vtable). В этом случае вызов виртуальной функции может генерироваться только внутри, если компилятор может статически определять фактический тип, для которого будет вызываться функция, а не только то, что он должен быть классом X или чем-то, полученным из X.
В основное время встроенная виртуальная функция имеет смысл, если у вас есть критическая ситуация с производительностью, и знайте, что класс будет часто использоваться таким образом, чтобы компилятор мог определить фактический тип статически (и, по крайней мере, один целевой компилятор оптимизирует вызов через указатель).
Ответ 2
Чтобы полностью ответить на этот вопрос, нужно понять, что свойство быть virtual
применяется независимо от самой функции и вызовов, сделанных для этой функции. Существуют виртуальные и не виртуальные функции. Существуют виртуальные и не виртуальные вызовы этих функций.
То же самое относится к свойству inline
. Существуют инелинные и нестрочные функции. И есть встроенные и неинтенсивные вызовы этих функций.
Эти свойства - virtual
и inline
- при применении к самой функции не конфликтуют. У них просто нет причин и никаких шансов на конфликт. Единственное, что спецификатор inline
изменяется для самой функции, состоит в том, что он изменяет правило одной определённой функции для этой функции: функция может быть определена в нескольких единицах перевода (и она должна быть определена в каждой единицы перевода, где она используется), Единственное, что изменит спецификатор virtual
, состоит в том, что класс, содержащий эту функцию, становится полиморфным. Это не влияет на саму функцию.
Таким образом, нет абсолютно никаких проблем при объявлении функции virtual
и inline
одновременно. Нет никаких оснований для конфликта. Это совершенно легально на языке С++.
struct S {
virtual void foo();
};
inline void S::foo() // virtual inline function - OK, whatever
{
}
Однако, когда люди задают этот вопрос, они обычно не интересуются свойствами самой функции, а скорее характеристиками вызовов, выполняемых этой функцией.
Определяющей особенностью виртуального вызова является то, что он разрешен во время выполнения, что означает, что в целом невозможно встроить истинные виртуальные вызовы:
S *s = new SomeType;
s->foo(); // virtual call, in general case cannot be inlined
Однако, если вызов сам по себе не является виртуальным (даже если он переходит к виртуальной функции), вложение не является проблемой вообще:
S *s = new SomeType;
s->S::foo(); // non-virtual call to a virtual function, can easily be inlined
Конечно, в некоторых случаях оптимизационный компилятор может определить цель виртуального вызова во время компиляции и встроить даже такой виртуальный вызов. В некоторых случаях это легко:
S ss;
ss.foo(); // formally a virtual call, but in practice it can easily be inlined
В некоторых случаях это сложнее, но все же выполнимо:
S *s = new S;
s->foo(); // virtual call, but a clever compiler might be able
// to figure out that it can be inlined
Ответ 3
У вас могут быть виртуальные функции как встроенные. Решение о вызове функции callline не просто выполняется во время компиляции. Это может быть в любое время между компиляцией и рутимом. Вы можете обратиться к этой статье с Herb Sutter. Inline Redux