Наследование классов и переопределение членов

Наследование класса Extend a class

Используйте ключевое слово extends для создания подкласса на основе суперкласса (родительского класса).

Ключевое слово super позволяет вызывать члены родительского класса (методы, конструкторы и т.д.) из подкласса.

class Television {
  void turnOn() {
     ...
     // Код, выполняющийся в методе родительского класса
  }
}

// SmartTelevision — подкласс, Television — родительский класс
class SmartTelevision extends Television {
  @override
  void turnOn() {
    super.turnOn(); // Вызов метода turnOn родительского класса
    // Уникальный код для подкласса
    ...
  }
}Code language: Dart (dart)

Пример: обычный телевизор выступает как родительский класс, а смарт-телевизор — как подкласс. Смарт-телевизор наследует возможности обычного телевизора.

extends имеет и другой вариант применения: работа с параметризованными типами из главы о дженериках.

Практический пример
class Television {
  void turnOn() {
    print("Включить телевизор, активировать базовый вывод изображения");
  }
}

// SmartTelevision — подкласс, Television — родительский класс
class SmartTelevision extends Television {
  @override
  void turnOn() {
    super.turnOn(); // Вызов метода turnOn родительского класса
    // Уникальный код для подкласса
    print("Смарт-телевизор: активировать сетевой модуль, загрузить главный экран интеллектуальной системы");
  }
}

void main() {
  // Экземпляр обычного телевизора
  Television normalTv = Television();
  print("===== Включение обычного телевизора =====");
  normalTv.turnOn();

  // Экземпляр смарт-телевизора
  SmartTelevision smartTv = SmartTelevision();
  print("\n===== Включение смарт-телевизора =====");
  smartTv.turnOn();
}Code language: Dart (dart)

Результат выполнения

D:\dartdemo\firstdart>dart run
Building package executable... (1.4s)
Built firstdart:firstdart.
===== Включение обычного телевизора =====
Включить телевизор, активировать базовый вывод изображения

===== Включение смарт-телевизора =====
Включить телевизор, активировать базовый вывод изображения

Переопределение членов Overriding members

1. Переопределяемые элементы

Подкласс может переопределять: методы экземпляра (в том числе операторы), геттеры и сеттеры.

2. Аннотация @override

Назначение: явно указать, что метод намеренно переопределяет член родительского класса и позволить компилятору выполнять проверки.

class Television {
  set contrast(int value) {}
}

class SmartTelevision extends Television {
  @override // Сообщает компилятору, что этот метод переопределяет метод родительского класса
  set contrast(num value) {}
}
Code language: JavaScript (javascript)

3. Правила корректного переопределения

  1. Возвращаемый тип: возвращаемый тип переопределяющего метода должен совпадать с типом родительского метода или быть его подтипом.
  2. Тип параметра: тип параметра переопределяющего метода должен совпадать с типом родительского метода или быть его надтипом. (Пример: intnum. num является надтипом int, поэтому это разрешено.)
  3. Количество позиционных параметров: если исходный метод имеет n позиционных параметров, переопределяющий метод также должен объявить ровно n позиционных параметров.
  4. Ограничения дженериков: обобщённый метод не может переопределять необобщённый метод и наоборот.

4. Ключевое слово covariant (особый случай сужения типа)

Стандартные правила запрещают сужать тип параметра (нисходящее приведение типов может вызвать ошибки во время выполнения) ;

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

При переопределении оператора == вы также обязательно должны переопределить геттер hashCode, унаследованный от Object.


noSuchMethod ()

1. Назначение

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

Без переопределения доступ к отсутствующему члену сразу генерирует ошибку NoSuchMethodError.

class A {
  @override
  void noSuchMethod(Invocation invocation) {
    print('You tried to use a non-existent member: ${invocation.memberName}');
  }
}
Code language: JavaScript (javascript)
  • Объект Invocation: хранит всю информацию о вызове (имя члена, параметры и т.д.)
2. Два условия вызова нереализованных методов (достаточно одного)
  1. Статический тип объекта-получателя вызова — dynamic ;
  2. Статический тип получателя объявляет этот нереализованный метод (он может быть абстрактным), а динамический тип получателя имеет свою реализацию noSuchMethod(), отличную от стандартной версии из Object.

Пример

class A {
  @override
  void noSuchMethod(Invocation invocation) {
    print('You tried to use a non-existent member: ${invocation.memberName}');
    // Дополнительный вывод параметров и типа вызова для полной информации
    print('Параметры вызова:${invocation.arguments}');
    print('Тип вызова:${invocation.runtimeType}');
  }
}

void main() {
  A obj = A();
  // Вызов несуществующего метода активирует noSuchMethod
  obj.hello("test", 123);
  // Обращение к несуществующему свойству
  obj.unknownValue;
}Code language: Dart (dart)
D:\dartdemo\firstdart>dart run
Building package executable...
Failed to build firstdart:firstdart:
bin/firstdart.dart:6:30: Error: The getter 'arguments' isn't defined for the type 'Invocation'.
 - 'Invocation' is from 'dart:core'.
Try correcting the name to the name of an existing getter, or defining a getter or field named 'arguments'.
    print('cal:${invocation.arguments}');
                             ^^^^^^^^^
bin/firstdart.dart:14:7: Error: The method 'hello' isn't defined for the type 'A'.
 - 'A' is from 'bin/firstdart.dart'.
Try correcting the name to the name of an existing method, or defining a method named 'hello'.
  obj.hello("test", 123);
      ^^^^^
bin/firstdart.dart:16:7: Error: The getter 'unknownValue' isn't defined for the type 'A'.
 - 'A' is from 'bin/firstdart.dart'.
Try correcting the name to the name of an existing getter, or defining a getter or field named 'unknownValue'.
  obj.unknownValue;Code language: PHP (php)

Наследование классов и переопределение членов

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

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