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

  Юрий  | 

  Обновл. 6 Янв 2020  | 

 13188

 ǀ   3 

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

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

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

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

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 (100 оценок, среднее: 4,88 из 5)
Загрузка...

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

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

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

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

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

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

    1. Аватар Da Da:

      нашел кого исправлять, аплодисменты

Добавить комментарий

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