Сравнивая виртуальные функции в C ++ и виртуальные таблицы в C, компиляторы в целом (и для достаточно больших проектов) справляются с работой девиртуализации?
Наивно, кажется, что у виртуальных функций в C ++ есть немного больше семантики, таким образом может быть легче девиртуализировать.
Обновление: Mooing Duck упомянул встроенные девиртуализированные функции. Быстрая проверка показывает пропущенные оптимизации с виртуальными таблицами:
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 ++ компилятор должен доказать, что объект является экземпляром определенного класса. Казалось бы, в первом случае доказательство сложнее. Тем не менее, виртуальные таблицы обычно модифицируются лишь в очень немногих местах, и что наиболее важно: просто потому, что они выглядят сложнее, не означает, что компиляторы не так хороши в этом (иначе вы можете поспорить, что ксоринг обычно быстрее, чем добавление двух целые числа).