Какую пользу компилятору дает новое ключевое слово final в C ++?

C ++ 11 позволит помечать классы и виртуальный метод как final , чтобы запретить производные от них или отменять их.

class Driver {
  virtual void print() const;
};
class KeyboardDriver : public Driver {
  void print(int) const final;
};
class MouseDriver final : public Driver {
  void print(int) const;
};
class Data final {
  int values_;
};

Это очень полезно, потому что оно сообщает читателю интерфейса кое-что о цели использования этого класса / метода. То, что пользователь получает диагностику, если он пытается переопределить, тоже может быть полезно.

Но есть ли преимущество с точки зрения компилятора? Может ли компилятор сделать что-нибудь по-другому, если он знает, что «этот класс никогда не будет производным от» или «эта виртуальная функция никогда не будет переопределена»?

Для final я в основном нашел только N2751, относящийся к нему. Просматривая некоторые из обсуждений, я обнаружил аргументы, исходящие от C ++ / CLI, но не нашел четкого намека на то, почему final может быть полезен для компилятора. Я думаю об этом, потому что я также вижу некоторые недостатки маркировки класса final : Для модульного тестирования защищенных функций-членов можно получить класс и вставить тестовый код. Иногда эти классы являются хорошими кандидатами на получение оценки final . В этих случаях этот метод был бы невозможен.

29
задан Doug T. 24 September 2011 в 12:06
поделиться

1 ответ

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

Например, рассмотрим этот код:

class Base
{
  public:
    virtual void foo() { }
    Base() { }
    ~Base();
};

void destroy(Base* b)
{
  delete b;
}

Многие компиляторы будут выдавать предупреждение для не виртуального деструктора b, когда наблюдается delete b. Если бы класс Derived унаследован от Base и имел свой собственный деструктор ~Derived, использование destroy на динамически размещаемом экземпляре Derived обычно (в соответствии со спецификацией поведения не определено) вызывает ~Base, но это не звоните ~Derived. Таким образом, операции очистки ~Derived не произойдут, и это может быть плохо (хотя в большинстве случаев, вероятно, не катастрофическим).

Если компилятор знает, что Base не может быть унаследован, тем не менее, не проблема, что ~Base не является виртуальным, потому что никакая производная очистка не может быть случайно пропущена. Добавление final к class Base дает компилятору информацию, чтобы не выдавать предупреждение.

Я точно знаю, что использование final таким образом подавит предупреждение с помощью Clang. Я не знаю, выдают ли здесь другие компиляторы предупреждение или учитывают ли они окончательность при определении того, следует ли выдавать предупреждение.

0
ответ дан 28 November 2019 в 01:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: