Безопасное переопределение виртуальных функций 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++)? Как избежать этих проблем?
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++ вы можете использовать ключевое слово
overrideclass 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