Вопрос по c++ – Реализация чистой виртуальной функции из абстрактного базового класса: имеет ли спецификатор переопределения какое-либо значение?

4
Фон

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

C ++ Virtual / Pure Virtual объяснилC ++ переопределяет чисто виртуальный метод с чисто виртуальным методомВопрос

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

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; }
};
@Hayt: я имею в виду, что функция переопределена или нетне определяется наличиемoverride ключевое слово. Это помощь для развития, а не помощь для компилятора. peppe
@peppe есть причины для реализации переопределения. Если вы изменяете сигнатуру в базовом классе (для не чистой виртуальной функции), все остальные все равно компилируются, и вы не получите никаких ошибок без переопределения. Hayt
@ KrzysztofBargieł: как помочь? Компилятор наверняка знает, что эта функция является переопределением.override для людей. peppe
Компилятор может знать, предназначена ли эта функция для переопределения чего-либо или нет, и генерировать ошибку, если это необходимо. Hayt

Ваш Ответ

4   ответа
1

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

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

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

2

ае вы получите ошибку (кроме как в примере с Питом)

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

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

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

ОтносительноЗачем хорошо, чтобы все переопределенные методы были объявленыoverride:

представь, что у тебя есть

class A
{
    virtual void Foo();
};

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

А потом ты меняешьFoo кconst функция вA, Безoverride это скомпилируется, но когда вы звонитеA->foo() и это объект BB->foo() не будет вызываться без каких-либо указаний, что-то там изменилось. Сoverride Вы получаете ошибку здесь.

8

Я не большой поклонник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 компилятор сообщит об ошибке.

3

Технически обе версии синтаксически верны и законны.override Спецификатор в основном предназначен для предотвращения непредвиденного поведения. Компилятор выдаст ошибку, как только встретит функцию-член, помеченную как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/override

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