Урок №159. Переопределение методов родительского класса

  Юрий  | 

  Обновл. 14 Авг 2020  | 

 14535

 ǀ   4 

Дочерние классы по умолчанию наследуют все методы родительского класса. На этом уроке мы рассмотрим, как это происходит, а также то, как можно изменить методы родительских классов в дочерних классах.

Вызов методов родительского класса

При вызове метода через объект дочернего класса, компилятор сначала смотрит, существует ли этот метод в дочернем классе. Если нет, то он начинает продвигаться по цепочке наследования вверх и проверяет, был ли этот метод определен в любом из родительских классов. Компилятор будет использовать первое найденное определение. Например:

Результат выполнения программы:

I am a Parent!
I am a Parent!

При вызове child.identify(), компилятор смотрит, определен ли метод identify() в классе Child. Нет, поэтому компилятор переходит к классу Parent. В классе Parent есть определение метода identify(), поэтому компилятор использует именно это определение.

Переопределение методов родительского класса


Однако, если бы мы определили метод identify() в классе Child, то использовалось бы именно это определение. Это означает, что мы можем заставить родительские методы работать по-другому с нашими дочерними классами, просто переопределяя их в дочерних классах!

В примере, приведенном выше, было бы лучше, если бы child.identify() выводил бы I am a Child!. Давайте изменим метод identify() в классе Child так, чтобы он возвращал правильный ответ.

Переопределение родительского метода в дочернем классе происходит как обычное определение метода:

Вот тот же код main(), что в примере, приведенном выше, но уже с внесенными изменениями в класс Child:

Результат:

I am a Parent!
I am a Child!

Обратите внимание, когда мы переопределяем родительский метод в дочернем классе, то дочерний метод не наследует спецификатор доступа родительского метода с тем же именем. Используется тот спецификатор доступа, который указан в дочернем классе. Таким образом, метод, определенный как private в родительском классе, может быть переопределен как public в дочернем классе, или наоборот!

Расширение функционала родительских методов

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

Чтобы метод дочернего класса вызывал метод родительского класса с тем же именем, нужно просто выполнить обычный вызов функции, но с добавлением имени родительского класса и оператора разрешения области видимости. В следующем примере мы выполним переопределение identify() в классе Child, вызывая сначала Parent::identify(), а затем добавляя уже свой код:

Вместе с:

Дает результат:

I am a Parent!
I am a Parent!
I am a Child!

При выполнении child.identify() выполняется вызов Child::identify(). В Child::identify() мы сначала вызываем Parent::identify(), который выводит I am a Parent!. Когда Parent::identify() завершает свое выполнение, Child::identify() продолжает свое выполнение и выводит I am a Child!.

Всё просто. Зачем тогда нужно использовать оператор разрешения области видимости (::)? А затем, что, если бы мы определили Child::identify() следующим образом:

То вызов метода identify() без указания оператора разрешения области видимости привел бы к вызову identify() в текущем классе, т.е. к Child::identify(). Затем снова вызов Child::identify() и ура — у нас получился бесконечный цикл. Поэтому использование оператора разрешения области видимости является обязательным условием при изменении методов родительского класса.


Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (114 оценок, среднее: 4,89 из 5)
Загрузка...

Комментариев: 4

  1. Аватар Алексей:

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

    Результат STATE: 0(false).

    Получается, что если вызывать метод (setFlag) не напрямую, а через другой метод (doSomething) РОДИТЕЛЬСКОГО класса (не переопределенный в дочернем), то вызовется метод (setFlag) родительского класса, хотя объект владеет переопределенным методом (setFlag).

    Теперь мой вопрос: есть ли способ решить данную проблему не прибегая к виртуальным методам?

  2. Аватар Снова я:

    У меня именно так и получилось в прошлом тестовом задании когда я решил что под каждый потомок класса Fruit заново перегружать оператор вывода << бредово и попытался вызвать << родительского класса для того чтобы вывести name и color и добавить к нему функционал вывода fiber.
    Но я так и не понял как вызвать родительский операторв вывода << . С обычной функцией и методом все просто . Вряд ли мне кто-то ответит (зайду завтра-послезавтра еще глянуть) , а пока полезу в интернет искать решение

    1. Аватар Пётр:

      Ответ для всех, кто также пытался это сделать (я, кстати, тоже)

  3. Аватар Александр:

    *** и ура — у нас получился бесконечный цикл

    у нас получилась рекурсия 🙂
    которая в С++ окажется весьма конечной, причем довольно быстро — вызов функций сожрет память на стеке и вылетит с ошибкой времени выполнения 🙂

Добавить комментарий для Александр Отменить ответ

Ваш E-mail не будет опубликован. Обязательные поля помечены *