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

Кто-нибудь знает о языковой функции или технике в 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. Не делайте свою функцию виртуальной. Однако на самом деле это не предотвращает затенение функции другим определением.

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

Удачи!

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

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

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

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

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

Когда вы можете использовать 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ключевое слово.

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

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

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

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

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

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

то есть:

Parent* obj = new Child();

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

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

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

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

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

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

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

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

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

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

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

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

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

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

int foo() { return 1; }

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

int foo() { return 2; }

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

Вот о чем он спрашивает.