Ну, на самом деле виртуальные функции всегда могут быть встроены , если они статически связаны друг с другом: предположим, у нас есть абстрактный класс Base
с виртуальной функцией F
и производными классами Derived1
и Derived2
:
class Base {
virtual void F() = 0;
};
class Derived1 : public Base {
virtual void F();
};
class Derived2 : public Base {
virtual void F();
};
Гипотетический вызов b->F();
(с b
типа Base*
), очевидно, является виртуальным. Но вы (или компилятор ...) могли бы переписать его примерно так (предположим, что typeof
- это typeid
-подобная функция, которая возвращает значение, которое можно использовать в switch
)
switch (typeof(b)) {
case Derived1: b->Derived1::F(); break; // static, inlineable call
case Derived2: b->Derived2::F(); break; // static, inlineable call
case Base: assert(!"pure virtual function call!");
default: b->F(); break; // virtual call (dyn-loaded code)
}
, хотя нам все еще нужен RTTI для typeof
, вызов может быть эффективно встроен путем, в основном, встраивания vtable в поток инструкций и специализации вызова для всех участвующих классов. Это также можно обобщить, специализируя лишь несколько классов (скажем, просто Derived1
):
switch (typeof(b)) {
case Derived1: b->Derived1::F(); break; // hot path
default: b->F(); break; // default virtual call, cold path
}