Сравнивая виртуальные функции в C ++ и виртуальные таблицы в C, делают ли компиляторы в целом (и для достаточно больших проектов) столь же хорошо работу с девиртуализацией?
Наивно, кажется, что это так. виртуальные функции в C ++ имеют немного больше семантики, поэтому их легче девиртуализировать.
Обновление: Муинг Дак упомянул встраивание девиртуализированных функций. Быстрая проверка показывает пропущенные оптимизации с виртуальными таблицами:
struct vtab {
int (*f)();
};
struct obj {
struct vtab *vtab;
int data;
};
int f()
{
return 5;
}
int main()
{
struct vtab vtab = {f};
struct obj obj = {&vtab, 10};
printf("%d\n", obj.vtab->f());
}
Мой GCC не будет встроить f, хотя он вызывается напрямую, то есть девиртуализированный. Эквивалент в C ++,
class A
{
public:
virtual int f() = 0;
};
class B
{
public:
int f() {return 5;}
};
int main()
{
B b;
printf("%d\n", b.f());
}
делает даже встроенным f. Итак, есть первое различие между C и C ++, хотя я не думаю, что добавленная семантика в версии C ++ уместна в этом случае.
Обновление 2: Для девиртуализации в C , компилятор должен доказать, что указатель функции в виртуальной таблице имеет определенное значение. Для девиртуализации в C ++ компилятор должен доказать, что объект является экземпляром определенного класса. Казалось бы, в первом случае доказательство сложнее. Однако виртуальные таблицы обычно модифицируются лишь в очень немногих местах, и, что наиболее важно: просто потому, что это выглядит сложнее, не означает, что компиляторы не так хороши в этом (иначе вы можете утверждать, что xoring обычно быстрее, чем добавление двух целые числа).