Безопасное переопределение виртуальных функций C++



у меня есть базовый класс с виртуальной функцией, и я хочу, чтобы переопределить функцию в производном классе. Есть ли способ заставить компилятор проверить, действительно ли функция, объявленная в производном классе, переопределяет функцию в базовом классе? Я хотел бы добавить какой-то макрос или что-то, что гарантирует, что я случайно не объявлю новую функцию вместо переопределения старой.



рассмотрим пример:



class parent {
public:
virtual void handle_event(int something) const {
// boring default code
}
};

class child : public parent {
public:
virtual void handle_event(int something) {
// new exciting code
}
};

int main() {
parent *p = new child();
p->handle_event(1);
}


здесь parent::handle_event() вызывается вместо child::handle_event(), потому что метод ребенка пропускает const объявление и поэтому объявляет новый метод. Это также может быть опечатка в имени функции или некоторые незначительные различия в типах параметров. Это также может легко произойти, если интерфейс базового класса изменяется, и где-то какой-то производный класс не был обновлен, чтобы отразить изменение.



есть ли способ избежать этой проблемы, могу ли я как-то сказать компилятору или какому-либо другому инструменту, чтобы проверить это для меня? Любой полезный компилятор флаги (желательно для G++)? Как избежать этих проблем?

783   8  

8 ответов:

Так как g++ 4.7 он понимает новый C++11 override ключевые слова:

class child : public parent {
    public:
      // force handle_event to override a existing function in parent
      // error out if the function with the correct signature does not exist
      void handle_event(int something) override;
};

что-то вроде C#'s override ключевое слово не является частью языка C++.

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

насколько я знаю, вы не можете просто сделать его абстрактным?

class parent {
public:
  virtual void handle_event(int something) const = 0 {
    // boring default code
  }
};

Я думал, что читаю дальше www.parashift.com что вы действительно можете реализовать абстрактный метод. Что имеет смысл лично для меня, единственное, что он делает, - это заставить подклассы реализовать его, никто ничего не сказал о том, что ему не разрешено иметь саму реализацию.

в MSVC, вы можете использовать CLR override ключевое слово, даже если вы не компилируете для среды CLR.

в g++ нет прямого способа обеспечить это во всех случаях; другие люди дали хорошие ответы о том, как поймать различия в сигнатурах с помощью -Woverloaded-virtual. В будущей версии, кто-то может добавить синтаксис, как __attribute__ ((override)) или эквивалент с использованием синтаксиса C++0x.

в MSVC++ вы можете использовать ключевое слово override

    class child : public parent {
    public:
      virtual void handle_event(int something) override {
        // new exciting code
      }
    };

override работает как для собственного кода, так и для кода CLR в MSVC++.

сделайте функцию абстрактной, чтобы у производных классов не было другого выбора, кроме как переопределить ее.

@Ray ваш код недействителен.

class parent {
public:
  virtual void handle_event(int something) const = 0 {
    // boring default code
  }
};

абстрактные функции не могут иметь тела, определенные в строке. Он должен быть изменен, чтобы стать

class parent {
public:
  virtual void handle_event(int something) const = 0;
};

void parent::handle_event( int something ) { /* do w/e you want here. */ }

Я бы предложил небольшое изменение в вашей логике. Это может или не может работать, в зависимости от того, что вам нужно сделать.

handle_event () все еще может выполнять "скучный код по умолчанию", но вместо того, чтобы быть виртуальным, в точке, где вы хотите, чтобы он выполнял "новый захватывающий код", базовый класс вызывает абстрактный метод (т. е. должен быть переопределен), который будет предоставлен вашим классом-потомком.

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

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

например, это предупреждение C4263 в Microsoft Visual C++.

Comments

    Ничего не найдено.