Есть ли способ предотвратить переопределение метода в подклассах?

Кто-нибудь знает какую-либо языковую функцию или технику в C++, чтобы предотвратить переопределение дочерним классом определенного метода в родительском классе?

class Base {
public:
    bool someGuaranteedResult() { return true; }
};

class Child : public Base {
public:
    bool someGuaranteedResult() { return false; /* Haha I broke things! */ }
};

Даже если это не виртуально, это все же разрешено (по крайней мере, в используемом мной компиляторе Metrowerks), все, что вы получаете, это предупреждение во время компиляции о скрытии не виртуальной унаследованной функции X.

14 ответов

Решение

Пара идей:

  1. Сделайте вашу функцию частной.
  2. Не делайте свою функцию виртуальной. Это на самом деле не предотвращает затенение функции другим определением.

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

Удачи!

Когда вы можете использовать final Спецификатор для виртуальных методов (введен в C++11), вы можете сделать это. Позвольте мне процитировать мой любимый сайт документации:

При использовании в объявлении виртуальной функции final указывает, что функция не может быть переопределена производными классами.

Адаптированный к вашему примеру, который будет выглядеть так:

class Base {
public:
    virtual bool someGuaranteedResult() final { return true; }
};

class Child : public Base {
public:
    bool someGuaranteedResult() { return false; /* Haha I broke things! */ }
};

Когда скомпилировано:

$ g++ test.cc -std=c++11
test.cc:8:10: error: virtual function ‘virtual bool Child::someGuaranteedResult()’
test.cc:3:18: error: overriding final function ‘virtual bool Base::someGuaranteedResult()’

Когда вы работаете с компилятором Microsoft, взгляните также на sealed ключевое слово.

Похоже, то, что вы ищете, является эквивалентом ключевого ключевого слова языка Java, которое предотвращает переопределение метода подклассом.

Как и другие здесь предположили, вы действительно не можете предотвратить это. Кроме того, кажется, что это довольно часто задаваемый вопрос.

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

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

предупреждение времени компиляции о скрытии не виртуальной унаследованной функции X.

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

Для пояснения, большинство из вас неправильно поняли его вопрос. Он не спрашивает о "переопределении" метода, он спрашивает, есть ли способ предотвратить "сокрытие" или нет. И простой ответ - "нет!".

Вот его пример еще раз

Родительский класс определяет функцию:

int foo() { return 1; }

Дочерний класс, наследующий Parent, определяет ту же функцию AGAIN (без переопределения):

int foo() { return 2; }

Вы можете сделать это на всех языках программирования. Ничто не мешает скомпилировать этот код (кроме настройки в компиляторе). Лучшее, что вы получите, - это предупреждение о том, что вы скрываете метод родителя. Если вы вызовете дочерний класс и вызовете метод foo, вы получите 2. Вы практически нарушили код.

Это то, что он спрашивает.

Я думаю, то, о чем вас предупреждает компилятор, скрывается!! Это на самом деле отменяется?

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

Это интересно. Попробуйте создать небольшую автономную тестовую программу для вашего компилятора.

Я искал то же самое и вчера пришел к этому [довольно старому] вопросу.

Сегодня я нашел подходящее ключевое слово C++11: final, Я подумал, что это может быть полезно для следующих читателей.

http://en.cppreference.com/w/cpp/language/final

Технически вы можете предотвратить переопределение виртуальных функций. Но вы никогда не сможете изменить или добавить больше. Это не полная помощь. Лучше использовать комментарий перед функцией, как предполагает faq lite.

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

Поэтому по умолчанию C++ делает то, что вы хотите.

В вашем примере ни одна функция не переопределена. Вместо этого он скрыт (это своего рода перерожденный случай перегрузки). Ошибка в коде класса Child. Как подсказывает csmba, все, что вы можете сделать, это изменить настройки вашего компилятора (если это возможно); все должно быть хорошо, если вы не используете стороннюю библиотеку, которая скрывает свои собственные функции.

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

Вы можете только надеяться, что пользователи, которые хотят использовать ваш код, а не чужие, будут осторожны с тем, как они ссылаются на ваш код и что они используют правильный тип указателя или используют полностью определенную область видимости.

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

то есть:

Parent* obj = new Child();

Методы C++ являются закрытыми и не могут быть переопределены по умолчанию.

  • Вы не можете переопределить приватный метод
  • Вы не можете переопределить неvirtual метод

Возможно, вы имеете в виду перегрузку?

Другие вопросы по тегам