Menu
Coddy logo textTech

Конструкторы и наследование

Часть раздела Объектно-ориентированное программирование путешествия по Dart на Coddy — урок 41 из 110.

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

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

class Person {
  String name;
  int age;
  
  Person(this.name, this.age);
}

class Student extends Person {
  String school;
  
  Student(String name, int age, this.school) : super(name, age);
}

В Dart 2.17 появились супер-параметры — более лаконичный синтаксис, который передает параметры напрямую в конструктор родительского класса:

class Student extends Person {
  String school;
  
  // super.name и super.age передаются напрямую в конструктор Person
  Student(super.name, super.age, this.school);
}

При работе с именованными конструкторами вы указываете, какой родительский конструктор следует вызвать:

class Employee extends Person {
  String department;
  
  Employee(super.name, super.age, this.department);
  
  Employee.intern(String name, this.department) : super(name, 18);
}

Основное правило простое: родительский класс должен быть полностью инициализирован до того, как дочерний класс добавит свои собственные свойства. Независимо от того, используете ли вы традиционный вызов super() или более новые супер-параметры, Dart гарантирует, что цепочка наследования правильно выстроена от родителя к потомку.

challenge icon

Задание

Легко

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

Вы организуете свой код в двух файлах:

  • product.dart: Определите здесь иерархию ваших продуктов:
    • Класс Product со свойствами String name и double price, конструктором, принимающим оба значения, и методом info(), который выводит [name]: $[price]
    • Класс Book, который расширяет Product и добавляет свойство String author. Используйте супер-параметры для передачи name и price в родительский конструктор
    • Класс Electronics, который расширяет Product и добавляет свойство int warranty (в месяцах). Используйте традиционный вызов super() в списке инициализации для передачи значений родителю
  • main.dart: Импортируйте файл с продуктами и продемонстрируйте оба подхода к наследованию конструкторов:
    • Создайте Book с именем 'Dart Essentials', ценой 29.99 и автором 'Jane Smith'
    • Вызовите его метод info(), затем выведите Author: [author]
    • Выведите пустую строку
    • Создайте Electronics с именем 'Wireless Mouse', ценой 45.50 и гарантией 24
    • Вызовите его метод info(), затем выведите Warranty: [warranty] months

Оба дочерних класса наследуют метод info() от Product без необходимости его переопределения. Ключевое различие заключается в том, как они вызывают родительский конструктор: Book использует более чистый синтаксис супер-параметров, в то время как Electronics использует традиционный подход с super() в списке инициализации.

Ожидаемый результат:

Dart Essentials: $29.99
Author: Jane Smith

Wireless Mouse: $45.5
Warranty: 24 months

Шпаргалка

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

Традиционный подход — явный вызов конструктора родителя в списке инициализации:

class Person {
  String name;
  int age;
  
  Person(this.name, this.age);
}

class Student extends Person {
  String school;
  
  Student(String name, int age, this.school) : super(name, age);
}

Super-параметры (Dart 2.17+) — прямая передача параметров в конструктор родителя:

class Student extends Person {
  String school;
  
  Student(super.name, super.age, this.school);
}

Именованные конструкторы — указание того, какой конструктор родителя следует вызвать:

class Employee extends Person {
  String department;
  
  Employee(super.name, super.age, this.department);
  
  Employee.intern(String name, this.department) : super(name, 18);
}

Попробуйте сами

import 'product.dart';

void main() {
  // TODO: Создайте Book с:
  // - name: 'Dart Essentials'
  // - price: 29.99
  // - author: 'Jane Smith'

  // TODO: Вызовите метод info() книги

  // TODO: Выведите "Author: [author]"

  // TODO: Выведите пустую строку

  // TODO: Создайте Electronics с:
  // - name: 'Wireless Mouse'
  // - price: 45.50
  // - warranty: 24

  // TODO: Вызовите метод info() электроники

  // TODO: Выведите "Warranty: [warranty] months"
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование