flutter
/

Dart Inheritance – Extending Classes and Reusing Code

Last Sync: Today

On this page

11
0%
5 min read
Remaining
5 minleft

Click any section to jump — progress syncs automatically

flutter

Dart Inheritance – Extending Classes and Reusing Code

What is Inheritance?

Inheritance is a fundamental concept of object‑oriented programming that allows a class to inherit properties and methods from another class. The class that inherits is called a subclass (or child class), and the class it inherits from is called a superclass (or parent class). Inheritance promotes code reuse and establishes a hierarchical relationship between classes.

Single Inheritance in Dart

Dart supports single inheritance – a class can extend only one superclass. This keeps the inheritance hierarchy simple and avoids the complexities of multiple inheritance (like the diamond problem). However, Dart provides mixins as a way to reuse code from multiple sources.

Basic Syntax: Using extends

To create a subclass, use the extends keyword followed by the superclass name. The subclass automatically inherits all non‑private members (fields and methods) of the superclass.

DARTRead-only
1
class Animal {
  String name;

  Animal(this.name);

  void eat() {
    print('$name is eating.');
  }
}

class Dog extends Animal {
  Dog(String name) : super(name);

  void bark() {
    print('$name is barking.');
  }
}

void main() {
  var dog = Dog('Buddy');
  dog.eat();  // Inherited from Animal
  dog.bark(); // Defined in Dog
}

The super Keyword

The super keyword refers to the superclass. It is used to call superclass constructors, methods, or access superclass properties. In the constructor, super() must be called in the initializer list.

DARTRead-only
1
class Person {
  String name;
  int age;

  Person(this.name, this.age);

  void introduce() {
    print('Hi, I am $name and I am $age years old.');
  }
}

class Student extends Person {
  String school;

  Student(String name, int age, this.school) : super(name, age);

  @override
  void introduce() {
    super.introduce(); // Call the superclass method
    print('I study at $school.');
  }
}

void main() {
  var student = Student('Alice', 20, 'Dart University');
  student.introduce();
}

Method Overriding

A subclass can override a method from the superclass by providing its own implementation. Use the @override annotation (optional but recommended) to indicate that you are intentionally overriding a method. The overridden method must have the same signature (return type and parameters).

DARTRead-only
1
class Shape {
  void draw() {
    print('Drawing a shape.');
  }
}

class Circle extends Shape {
  @override
  void draw() {
    print('Drawing a circle.');
  }
}

void main() {
  Shape shape = Circle();
  shape.draw(); // Output: Drawing a circle.
}

Inheritance and Constructors

Constructors are not inherited, but a subclass must call a constructor of the superclass. If the superclass doesn't have a default constructor (a constructor with no parameters), you must explicitly call a specific superclass constructor using super in the initializer list.

DARTRead-only
1
class Vehicle {
  String brand;

  Vehicle(this.brand); // No default constructor
}

class Car extends Vehicle {
  String model;

  Car(String brand, this.model) : super(brand); // Must call super
}

void main() {
  var car = Car('Toyota', 'Camry');
}

Preventing Inheritance: final and sealed Classes

You can prevent a class from being extended by marking it final (cannot be extended) or sealed (can be extended only within the same library). This is useful for creating immutable or restricted hierarchies.

DARTRead-only
1
final class Constants {
  static const pi = 3.14;
}

// class MyClass extends Constants {} // Error

sealed class Result {}

class Success extends Result {}
class Error extends Result {}

The covariant Keyword

When overriding a method, you can narrow the type of a parameter using the covariant keyword. This allows you to accept a more specific subtype than the superclass method.

DARTRead-only
1
class Animal {}
class Dog extends Animal {}

class AnimalHandler {
  void handle(Animal animal) {
    print('Handling animal');
  }
}

class DogHandler extends AnimalHandler {
  @override
  void handle(covariant Dog animal) {
    print('Handling dog');
  }
}

Common Mistakes

    • Forgetting to call super when the superclass has no default constructor – leads to a compile error.
    • Accidentally overriding a method without @override – can lead to subtle bugs if the superclass method signature changes.
    • Overriding a method and changing its parameter type – not allowed unless using covariant.
    • Trying to extend a final class – compile error.
    • Confusing inheritance with composition – sometimes composition is a better design choice.

Complete Example

DARTRead-only
1
class Employee {
  String name;
  double salary;

  Employee(this.name, this.salary);

  void work() {
    print('$name is working.');
  }

  void displayInfo() {
    print('Name: $name, Salary: \$$salary');
  }
}

class Manager extends Employee {
  int teamSize;

  Manager(String name, double salary, this.teamSize) : super(name, salary);

  @override
  void work() {
    super.work();
    print('$name is also managing a team of $teamSize people.');
  }

  void conductMeeting() {
    print('$name is conducting a meeting.');
  }
}

void main() {
  var emp = Employee('John', 50000);
  emp.work();
  emp.displayInfo();

  var mgr = Manager('Alice', 80000, 5);
  mgr.work();
  mgr.conductMeeting();
  mgr.displayInfo();
}

Key Takeaways

    • Inheritance allows a class to reuse code from another class.
    • Use extends to create a subclass.
    • Dart supports single inheritance only.
    • Use super to refer to the superclass and call its constructor or methods.
    • Override methods with @override to provide subclass‑specific behavior.
  • -A subclass must call a superclass constructor (implicitly or explicitly).
    • Use final or sealed to prevent inheritance.
    • The covariant keyword allows narrowing parameter types in overrides.

Try it yourself

class Animal {
  String name;
  Animal(this.name);
  void speak() {
    print('$name makes a sound.');
  }
}

class Dog extends Animal {
  Dog(String name) : super(name);
  @override
  void speak() {
    print('$name barks.');
  }
}

void main() {
  var dog = Dog('Rex');
  dog.speak();
}

Test Your Knowledge

Q1
of 4

Which keyword is used to create a subclass in Dart?

A
implements
B
extends
C
with
D
inherits
Q2
of 4

How many classes can a Dart class extend?

A
0
B
1
C
2
D
Unlimited
Q3
of 4

What does the `super` keyword refer to?

A
The current class
B
The superclass
C
The object's parent in the widget tree
D
A static method
Q4
of 4

What is the output of this code? class A { void foo() { print('A'); } } class B extends A { @override void foo() { print('B'); } } void main() { A obj = B(); obj.foo(); }

A
A
B
B
C
Error
D
Nothing

Frequently Asked Questions

Can a Dart class extend multiple classes?

No, Dart supports single inheritance – a class can only extend one superclass. However, you can implement multiple interfaces and use mixins to reuse code from multiple sources.

How do I call the superclass constructor?

Use super() in the initializer list of the subclass constructor. For example: Dog(String name) : super(name);.

What is the difference between `extends` and `implements`?

extends creates a subclass that inherits the implementation of the superclass. implements forces a class to provide its own implementation of all methods and properties declared in the implemented class (or interface). A class can implement multiple interfaces.

Is the `@override` annotation mandatory?

No, it's optional. However, it's a good practice because it tells the reader that the method is intended to override a superclass method, and it helps the compiler catch errors if the superclass method signature changes.

Can I override a property (field)?

In Dart, fields are not overridden; they are hidden. If you declare a field with the same name in a subclass, it shadows the superclass field. To achieve polymorphic behavior, use getters and setters.

What is the `covariant` keyword used for?

It allows you to narrow the type of a parameter when overriding a method. For example, you can override void handle(Animal animal) with void handle(covariant Dog animal).

How can I prevent a class from being extended?

Mark the class as final (cannot be extended anywhere) or sealed (can only be extended within the same library). For example: final class MyClass {}.

Can a subclass access private members of the superclass?

No, private members (those starting with _) are only accessible within the same library (file). If the subclass is in a different file, it cannot access them.

Previous

dart constructors

Next

dart polymorphism

Related Content

Need help?

Explore our comprehensive docs or start a chat with our tech experts.