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

<p>у меня есть базовый класс с виртуальной функцией, и я хочу переопределить эту функцию в производном классе. есть ли способ заставить компилятор проверить, переписывает ли функция, которую я объявил в производном классе, функцию в базовом классе? я хотел бы добавить некоторый макрос или что-то, что гарантирует, что я случайно не объявил новую функцию, вместо того, чтобы переопределить старую.</p><p>возьмите этот пример:</p><pre><code>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); } </code></pre><p>здесь <code>parent::handle\_event()</code> вызывается вместо <code>child::handle\_event()</code>, потому что дочерний метод пропускает объявление <code>const</code> и поэтому объявляет новый метод. это также может быть опечатка в имени функции или небольшая разница в типах параметров. это также может легко произойти, если интерфейс базового класса изменится, и где-то некоторый производный класс не будет обновлен, чтобы отразить изменение.</p><p>есть ли какой-то способ избежать этой проблемы, могу ли я как-нибудь сказать компилятору или другому инструменту проверить это для меня? любые полезные флаги компилятора (желательно для g ++)? как избежать этих проблем?</p>

<p>начиная с g ++ 4.7 он понимает новое ключевое слово c++ 11 <code>override</code>:</p><pre><code>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; }; </code></pre>

<p>что-то вроде ключевого слова <code>override</code> в c # не является частью c++.</p><p>в gcc <code>-woverloaded-virtual</code> предостерегает от сокрытия виртуальной функции базового класса с функцией с тем же именем, но с достаточно другой сигнатурой, что она не переопределяет ее. это, однако, не защитит вас от сбоя при переопределении функции из-за неправильного написания самого имени функции.</p>

<p>насколько я знаю, ты не можешь просто сделать это абстрактным?</p><pre><code>class parent { public: virtual void handle\_event(int something) const = 0 { // boring default code } }; </code></pre><p>я думал, что прочитал на www.parashift.com, что вы можете реализовать абстрактный метод. что имеет смысл для меня лично, единственное, что он делает, это заставляет подклассы реализовывать его, никто ничего не сказал о том, что ему не разрешено иметь саму реализацию.</p>

<p>в msvc вы можете использовать ключевое слово clr <code>override</code>, даже если вы не компилируете для clr.</p><p>в g ++ нет прямого способа обеспечить это во всех случаях; другие люди дали хорошие ответы о том, как отследить различия в сигнатурах с помощью <code>-woverloaded-virtual</code>. в будущей версии кто-то может добавить синтаксис, такой как <code>\_\_attribute\_\_ ((override))</code> или эквивалент, используя синтаксис c++ 0x.</p>

<p>в msvc++ вы можете использовать <a href="http://msdn.microsoft.com/en-us/library/41w3sh1c%28vs.80%29.aspx">ключевое слово <code>override</code></a> </p><pre> класс child: public parent { public: virtual void handle\_event (int что-то) <b>переопределение</b> { // новый захватывающий код } }; </pre><p><code>override</code> работает как для собственного, так и для clr-кода в msvc++.</p>

<p>сделайте функцию абстрактной, чтобы у производных классов не было другого выбора, кроме как переопределить ее.</p><p>@ray ваш код недействителен.</p><pre><code>class parent { public: virtual void handle\_event(int something) const = 0 { // boring default code } }; </code></pre><p>абстрактные функции не могут иметь тела, определенные в строке. это должно быть изменено, чтобы стать</p><pre><code>class parent { public: virtual void handle\_event(int something) const = 0; }; void parent::handle\_event( int something ) { /* do w/e you want here. */ } </code></pre>

<p>я бы предложил небольшое изменение в вашей логике. это может или не может работать, в зависимости от того, что вам нужно сделать.</p><p>handle\_event () по-прежнему может выполнять "скучный код по умолчанию", но вместо того, чтобы быть виртуальным, в тот момент, когда вы хотите, чтобы он выполнял "новый захватывающий код", базовый класс должен вызывать абстрактный метод (т. е. must-be-overridden) метод это будет предоставлено вашим потомком класса.</p><p>правка: и если позже вы решите, что некоторые из ваших классов-потомков <em>не</em> должны предоставить "новый захватывающий код", то вы можете изменить реферат на виртуальный и предоставить пустую реализацию базового класса этого "вставленного" функциональность.</p>

<p>ваш компилятор может иметь предупреждение о том, что он может сгенерировать, если функция базового класса станет скрытой. если это так, включите его. это позволит выявить конфликты и различия в списках параметров. к сожалению, это не обнаружит орфографическую ошибку.</p><p>например, это предупреждение c4263 в microsoft visual c++.</p>