Задний план

Я только что наткнулся на вариант использования override спецификатора, который , насколько я могу судить, кажется избыточным, а также без какого-либо особого семантического значения, но, возможно, я что-то упускаю, отсюда и этот вопрос. Прежде чем продолжить, я должен указать, что я пытался найти ответ на него здесь, на SO, но ближайшими, которые я получил, были следующие потоки, на самом деле не отвечающие на мой запрос (возможно, кто-то может указать на вопросы и ответы, которые на самом деле уже отвечают на мои вопрос).

Вопрос

Рассмотрим следующий абстрактный класс:

struct Abstract {
  virtual ~Abstract() {};
  virtual void foo() = 0;
};

Есть ли какая-либо причина использовать спецификатор override при реализации foo() в неабстрактном классе, производном непосредственно от Abstract (как в DerivedB ниже)? То есть, когда реализация foo() уже требуется, чтобы производный класс был неабстрактным (и на самом деле ничего не переопределял)?

/* "common" derived class implementation, in my personal experience
   (include virtual keyword for semantics) */
struct DerivedA : public Abstract {
  virtual void foo() { std::cout << "A foo" << std::endl; }
};

/* is there any reason for having the override specifier here? */
struct DerivedB : public Abstract {
  virtual void foo() override { std::cout << "B foo" << std::endl; }
};
c++
4
dfrib 7 Сен 2016 в 15:49

4 ответа

Лучший ответ

Я не большой поклонник override, но, если предположить, что это что-то, что вы сочтете полезным в целом, тогда да, добавление override к виртуальной функции, которая заменяет чистые виртуальные функции, полезно. Рассмотрим этот довольно надуманный пример:

struct Base {
    virtual void f() = 0;
};

struct Derived : Base {
    virtual void f();
    virtual void f(int);
};

Теперь предположим, что сопровождающий Base (возможно, даже ваше будущее) изменяет Base, чтобы он выглядел так:

struct Base {
    virtual void f(int) = 0;
};

Теперь поведение Derived незаметно изменилось. С override компилятор сообщит об ошибке.

9
Pete Becker 7 Сен 2016 в 12:55

Что касается почему хорошо, если были объявлены все переопределенные методы override:…

class Abstract {
    virtual void foo() { ...}
}; 

class Derived : public Abstract {
    void foo() override { ... }
};

Теперь, если подпись Abstract::foo изменится, скажем,

class Abstract {
    virtual void foo(int bar) { ...}
}; 

Компилятор выдаст ошибку в Derived::foo, поскольку он больше не переопределяет функцию Abstract, чего не было бы без квалификатора override. Это поможет вам лучше поддерживать ваш код. Однако в вашем конкретном случае (т.е. с чистыми виртуальными объявлениями) также будет выдана ошибка. Так что использование override в основном считается "хорошей практикой", я думаю. Подробнее по этой теме: http://en.cppreference.com/w/cpp/language/ переопределить

3
Felix Lauer 7 Сен 2016 в 13:03

Основным преимуществом override здесь будет облегчение сопровождения. Рассмотрим ниже:

class Foo
{
public: 
    virtual void foo() = 0;
};
class Derived : public Foo
{
public:
    //....
    virtual void foo(double x) override
    {
         //This throws error
    }
};

Как вы можете видеть выше, компилятор выдаст ошибку, если вы скомпилируете вышеуказанное. Что может случиться, так это то, что компилятор будет жаловаться на то, что функция не имеет такой же подписи. Без ключевого слова override результат был бы другим.

1
Arnav Borborah 7 Сен 2016 в 13:06

В случае чисто виртуальных функций и компиляций нет. Вы все равно получите сообщение об ошибке (кроме как в примере от Пита)

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

Еще одно преимущество - при чтении объявления вы знаете, что это производный метод от базового класса.

Также рекомендуется просто привыкнуть объявлять все переопределенные методы с помощью override. Так зачем здесь иметь значение и иметь противоречивый стиль.

Что касается почему хорошо, если были объявлены все переопределенные методы override:

Что касается почему хорошо, если были объявлены все переопределенные методы {{X0}}:…

class A
{
    virtual void Foo();
};

class B: public A
{
    virtual void Foo() override;
};

Что касается почему хорошо, если были объявлены все переопределенные методы Foo:…

2
Hayt 7 Сен 2016 в 13:04