Popular Searches
Popular Course Categories
Popular Courses

Inheritance in Dart

Object-Oriented Programming in Dart

Inheritance in Dart

Inheritance is one of the fundamental concepts of Object-Oriented Programming (OOP) in Dart. It allows one class to acquire and reuse properties and methods from another class. Inheritance helps developers create reusable, organized, and maintainable code.

In Dart and Flutter development, inheritance is important because many application components are built using classes and common parent-child relationships. JustAcademy's Flutter curriculum includes Object-Oriented Programming in Dart along with classes, objects, constructors, inheritance, polymorphism, and abstraction. :contentReference[oaicite:0]{index=0}

Flutter Training Course: https://www.justacademy.co/course-detail/flutter-training

Course Demo Registration: https://www.justacademy.co/register-for-course-demo


1. What is Inheritance?

Inheritance is an OOP mechanism in which a child class derives from a parent class and can use members defined by that parent.

In Dart, inheritance between classes is created using the extends keyword.

class Animal {
  void eat() {
    print('Animal is eating');
  }
}

class Dog extends Animal {
  void bark() {
    print('Dog is barking');
  }
}

void main() {
  Dog dog = Dog();

  dog.eat();
  dog.bark();
}

Output:

Animal is eating
Dog is barking

The Dog class inherits the eat() method from the Animal class.


2. Important Terms in Inheritance

Term Meaning
Parent Class The class whose members are inherited.
Child Class The class that inherits from another class.
Superclass Another name for the parent class.
Subclass Another name for the child class.
extends Keyword used to create class inheritance.
super Used to access members of the superclass.
@override Annotation used when a subclass provides a new implementation of an inherited member.

3. Why Use Inheritance?

Inheritance can be useful for several reasons:

  • Code reusability
  • Reducing duplicate code
  • Creating logical parent-child relationships
  • Extending existing functionality
  • Supporting polymorphism
  • Improving maintainability
  • Creating common abstractions

4. Basic Syntax of Inheritance

The basic syntax is:

class Parent {
  // Parent members
}

class Child extends Parent {
  // Child members
}

The Child class can use accessible members inherited from Parent and can also define its own members.


5. Simple Real-World Example

Consider a real-world relationship between a general Vehicle and a specific Car.

class Vehicle {
  void start() {
    print('Vehicle started');
  }

  void stop() {
    print('Vehicle stopped');
  }
}

class Car extends Vehicle {
  void drive() {
    print('Car is driving');
  }
}

void main() {
  Car car = Car();

  car.start();
  car.drive();
  car.stop();
}

Output:

Vehicle started
Car is driving
Vehicle stopped

Car automatically gets access to the inherited start() and stop() methods.


6. Inherited Properties

A child class can access accessible instance properties inherited from its parent.

class Person {
  String name = 'Rahul';
  int age = 25;
}

class Student extends Person {
  String course = 'Flutter';
}

void main() {
  Student student = Student();

  print(student.name);
  print(student.age);
  print(student.course);
}

Output:

Rahul
25
Flutter

The Student class has its own course property and also gets access to the inherited name and age properties.


7. Inherited Methods

Child classes can use methods inherited from the parent class.

class Employee {
  void login() {
    print('Employee logged in');
  }

  void logout() {
    print('Employee logged out');
  }
}

class Developer extends Employee {
  void writeCode() {
    print('Developer is writing code');
  }
}

void main() {
  Developer developer = Developer();

  developer.login();
  developer.writeCode();
  developer.logout();
}

The Developer object can call all accessible methods inherited from Employee.


8. Adding New Functionality in a Child Class

A child class does not have to use only inherited functionality. It can add additional properties and methods.

class Employee {
  String name;

  Employee(this.name);

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

class Developer extends Employee {
  String programmingLanguage;

  Developer(
    String name,
    this.programmingLanguage,
  ) : super(name);

  void writeCode() {
    print('$name is writing $programmingLanguage code');
  }
}

void main() {
  Developer developer = Developer('Rahul', 'Dart');

  developer.work();
  developer.writeCode();
}

Here, Developer extends the functionality of Employee.


9. Parent and Child Constructors

Constructors are not inherited by subclasses. A child class defines its own constructors and can invoke a parent constructor using super.

class Person {
  String name;

  Person(this.name);
}

class Student extends Person {
  int age;

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

void main() {
  Student student = Student('Amit', 21);

  print(student.name);
  print(student.age);
}

The expression super(name) calls the constructor of the parent class.


10. Understanding the super Keyword

The super keyword refers to the superclass portion of the current object. It is commonly used to:

  • Call a superclass constructor.
  • Call a superclass method.
  • Access an inherited member when needed.

Calling a Parent Constructor

class Person {
  String name;

  Person(this.name);
}

class Student extends Person {
  Student(String name) : super(name);
}

Calling a Parent Method

class Employee {
  void work() {
    print('Employee is working');
  }
}

class Developer extends Employee {
  @override
  void work() {
    super.work();
    print('Developer is writing code');
  }
}

11. Method Overriding in Inheritance

A child class can provide its own implementation of an inherited method. This is called method overriding.

class Animal {
  void sound() {
    print('Animal makes a sound');
  }
}

class Dog extends Animal {
  @override
  void sound() {
    print('Dog barks');
  }
}

void main() {
  Dog dog = Dog();

  dog.sound();
}

Output:

Dog barks

The @override annotation clearly indicates that Dog is providing its own implementation of the inherited sound() method.


12. Why Use @override?

The @override annotation communicates that a member is intended to override an inherited member and helps Dart's analyzer detect mistakes.

class Animal {
  void sound() {
    print('Animal sound');
  }
}

class Cat extends Animal {
  @override
  void sound() {
    print('Cat meows');
  }
}

Using @override makes the code easier for other developers to understand and maintain.


13. Inheritance and Polymorphism

Inheritance and polymorphism are closely related. A variable of a parent type can refer to an object of a child type, and overridden behavior can be selected according to the actual object.

class Animal {
  void sound() {
    print('Animal sound');
  }
}

class Dog extends Animal {
  @override
  void sound() {
    print('Dog barks');
  }
}

class Cat extends Animal {
  @override
  void sound() {
    print('Cat meows');
  }
}

void main() {
  Animal animal1 = Dog();
  Animal animal2 = Cat();

  animal1.sound();
  animal2.sound();
}

Output:

Dog barks
Cat meows

This is an example of runtime polymorphic behavior using an inheritance hierarchy.


14. Single Inheritance

In single inheritance, one child class directly extends one parent class.

class Animal {
  void eat() {
    print('Animal eats');
  }
}

class Dog extends Animal {
  void bark() {
    print('Dog barks');
  }
}

Structure:

Animal
   |
   v
  Dog

15. Multilevel Inheritance

In multilevel inheritance, a class extends another class that itself extends another class.

class Animal {
  void eat() {
    print('Animal eats');
  }
}

class Mammal extends Animal {
  void walk() {
    print('Mammal walks');
  }
}

class Dog extends Mammal {
  void bark() {
    print('Dog barks');
  }
}

void main() {
  Dog dog = Dog();

  dog.eat();
  dog.walk();
  dog.bark();
}

Structure:

Animal
   |
   v
Mammal
   |
   v
  Dog

The Dog class can access inherited members from both Mammal and Animal, subject to Dart's access rules.


16. Hierarchical Inheritance

In hierarchical inheritance, multiple child classes extend the same parent class.

class Animal {
  void eat() {
    print('Animal eats');
  }
}

class Dog extends Animal {
  void bark() {
    print('Dog barks');
  }
}

class Cat extends Animal {
  void meow() {
    print('Cat meows');
  }
}

class Cow extends Animal {
  void moo() {
    print('Cow moos');
  }
}

Structure:

        Animal
       /   |   \
      /    |    \
    Dog   Cat   Cow

17. Does Dart Support Multiple Class Inheritance?

Dart does not allow a class to extend multiple classes directly.

For example, this is not valid:

// Not valid Dart:

class A {
}

class B {
}

// A class cannot extend both A and B:
// class C extends A, B {}

Dart provides other mechanisms, such as mixins and interfaces, for sharing behavior or contracts across multiple types.


18. Inheritance with Abstract Classes

An abstract class can define a common contract that subclasses implement.

abstract class Shape {
  double calculateArea();
}

class Circle extends Shape {
  double radius;

  Circle(this.radius);

  @override
  double calculateArea() {
    return 3.14 * radius * radius;
  }
}

class Rectangle extends Shape {
  double width;
  double height;

  Rectangle(this.width, this.height);

  @override
  double calculateArea() {
    return width * height;
  }
}

void main() {
  Shape circle = Circle(5);
  Shape rectangle = Rectangle(10, 5);

  print(circle.calculateArea());
  print(rectangle.calculateArea());
}

The abstract parent class defines the required behavior, while the subclasses provide the implementation.


19. Practical Example: Person and Student

class Person {
  String name;
  int age;

  Person(this.name, this.age);

  void displayPerson() {
    print('Name: $name');
    print('Age: $age');
  }
}

class Student extends Person {
  String course;

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

  void study() {
    print('$name is studying $course');
  }
}

void main() {
  Student student = Student(
    'Rahul',
    21,
    'Flutter',
  );

  student.displayPerson();
  student.study();
}

The Student class reuses common person information while adding student-specific behavior.


20. Practical Example: Employee and Developer

class Employee {
  String name;
  double salary;

  Employee(this.name, this.salary);

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

class Developer extends Employee {
  String language;

  Developer(
    String name,
    double salary,
    this.language,
  ) : super(name, salary);

  void writeCode() {
    print('$name is writing $language code');
  }
}

void main() {
  Developer developer = Developer(
    'Amit',
    60000,
    'Dart',
  );

  developer.work();
  developer.writeCode();
}

21. Practical Example: Vehicle and Car

class Vehicle {
  String brand;

  Vehicle(this.brand);

  void start() {
    print('$brand vehicle started');
  }
}

class Car extends Vehicle {
  int doors;

  Car(
    String brand,
    this.doors,
  ) : super(brand);

  void showDoors() {
    print('Number of doors: $doors');
  }
}

void main() {
  Car car = Car('Toyota', 4);

  car.start();
  car.showDoors();
}

22. Practical Example: Bank Account

class BankAccount {
  String accountHolder;
  double balance;

  BankAccount(this.accountHolder, this.balance);

  void deposit(double amount) {
    balance += amount;
    print('Deposited: $amount');
  }

  void displayBalance() {
    print('Balance: $balance');
  }
}

class SavingsAccount extends BankAccount {
  double interestRate;

  SavingsAccount(
    String accountHolder,
    double balance,
    this.interestRate,
  ) : super(accountHolder, balance);

  void calculateInterest() {
    double interest = balance * interestRate / 100;
    print('Interest: $interest');
  }
}

void main() {
  SavingsAccount account = SavingsAccount(
    'Rahul',
    50000,
    5,
  );

  account.deposit(5000);
  account.calculateInterest();
  account.displayBalance();
}

The child class reuses banking functionality while adding savings-account-specific behavior.


23. Practical Example: E-Commerce Product

class Product {
  String name;
  double price;

  Product(this.name, this.price);

  void displayProduct() {
    print('Product: $name');
    print('Price: $price');
  }
}

class ElectronicsProduct extends Product {
  int warrantyYears;

  ElectronicsProduct(
    String name,
    double price,
    this.warrantyYears,
  ) : super(name, price);

  void displayWarranty() {
    print('Warranty: $warrantyYears years');
  }
}

void main() {
  ElectronicsProduct product = ElectronicsProduct(
    'Laptop',
    55000,
    2,
  );

  product.displayProduct();
  product.displayWarranty();
}

24. Practical Example: User and Admin

class User {
  String name;

  User(this.name);

  void login() {
    print('$name logged in');
  }
}

class Admin extends User {
  Admin(String name) : super(name);

  void manageUsers() {
    print('$name can manage users');
  }
}

void main() {
  Admin admin = Admin('Admin');

  admin.login();
  admin.manageUsers();
}

25. Inheritance in Flutter

Flutter development makes extensive use of class-based programming. For example, developers commonly create custom widgets by extending Flutter widget classes.

import 'package:flutter/material.dart';

class WelcomeScreen extends StatelessWidget {
  const WelcomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Center(
        child: Text('Welcome to Flutter'),
      ),
    );
  }
}

In this example:

  • WelcomeScreen is a custom class.
  • It extends StatelessWidget.
  • The build() method is overridden.
  • The constructor uses super.key to pass the key to the superclass constructor.

Inheritance and overriding are therefore practical concepts in normal Flutter widget development.


26. Inheritance vs Composition

Inheritance is not always the best way to reuse functionality. Another important design technique is composition.

Inheritance

class Animal {
  void eat() {
    print('Eating');
  }
}

class Dog extends Animal {
}

This represents an "is-a" relationship: a Dog is an Animal.

Composition

class Engine {
  void start() {
    print('Engine started');
  }
}

class Car {
  Engine engine = Engine();

  void startCar() {
    engine.start();
    print('Car started');
  }
}

This represents a "has-a" relationship: a Car has an Engine.

Choose inheritance when there is a genuine subtype relationship. Use composition when an object is better modeled as being composed of other objects.


27. Advantages of Inheritance

  • Code Reusability: Common code can be placed in a parent class.
  • Less Duplication: Child classes can reuse inherited functionality.
  • Extensibility: Child classes can add specialized functionality.
  • Polymorphism: Parent types can represent different child objects.
  • Maintainability: Shared behavior can be maintained in one location.
  • Organization: Related classes can be structured into meaningful hierarchies.

28. Disadvantages and Limitations of Inheritance

  • Deep inheritance hierarchies can become difficult to understand.
  • Changes to a parent class can affect multiple subclasses.
  • Inheritance creates a relatively strong relationship between parent and child classes.
  • It may be inappropriate when there is no genuine subtype relationship.
  • Composition can sometimes provide a more flexible design.

29. Important Rules of Inheritance in Dart

  • A class can directly extend one superclass.
  • The extends keyword is used for class inheritance.
  • Constructors are not inherited.
  • A child constructor can invoke a parent constructor using super.
  • Child classes can add new properties and methods.
  • Child classes can override inherited methods.
  • The @override annotation should be used to clearly mark overrides.
  • Abstract classes can define contracts for subclasses.
  • Dart uses mixins and interfaces for other forms of code reuse and abstraction rather than multiple class inheritance.

30. Common Mistakes in Inheritance

Mistake 1: Using Inheritance Without an "Is-A" Relationship

Inheritance should represent a meaningful subtype relationship.

For example, Dog extends Animal is a natural relationship, while unrelated classes should generally not be connected merely to reuse a few methods.

Mistake 2: Forgetting super in Constructors

class Person {
  String name;

  Person(this.name);
}

class Student extends Person {
  int age;

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

The super(name) call initializes the inherited name field through the parent constructor.

Mistake 3: Not Using @override

When redefining an inherited method, explicitly marking the method with @override improves clarity and analyzer support.

Mistake 4: Creating Very Deep Hierarchies

Prefer simple and understandable class relationships. If a hierarchy becomes unnecessarily deep, consider whether composition, interfaces, or mixins would be more appropriate.


31. Best Practices for Inheritance

  1. Use inheritance when there is a clear subtype relationship.
  2. Keep parent classes focused on common behavior.
  3. Keep child classes focused on specialized behavior.
  4. Use @override for overridden methods.
  5. Use super when parent initialization or behavior is required.
  6. Avoid unnecessary inheritance.
  7. Avoid excessively deep inheritance hierarchies.
  8. Prefer composition when a "has-a" relationship is more appropriate.
  9. Use abstract classes when subclasses must follow a common contract.
  10. Use polymorphism to make code work with abstractions rather than concrete implementations.

32. Inheritance and Access to Private Members

Dart's privacy mechanism is based on library boundaries rather than class-based private/protected keywords. Identifiers beginning with an underscore are private to the library where they are declared.

class Parent {
  String _secret = 'Private library member';

  void showSecret() {
    print(_secret);
  }
}

class Child extends Parent {
  void display() {
    showSecret();
  }
}

The child can use inherited public API such as showSecret(). The exact visibility of underscore-prefixed members depends on whether the classes are in the same Dart library.


33. Complete Inheritance Example

class Employee {
  String name;
  double salary;

  Employee(this.name, this.salary);

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

  void displayDetails() {
    print('Name: $name');
    print('Salary: $salary');
  }
}

class Developer extends Employee {
  String language;

  Developer(
    String name,
    double salary,
    this.language,
  ) : super(name, salary);

  @override
  void work() {
    print('$name is developing using $language');
  }

  void writeCode() {
    print('$name is writing code');
  }
}

class Designer extends Employee {
  String designTool;

  Designer(
    String name,
    double salary,
    this.designTool,
  ) : super(name, salary);

  @override
  void work() {
    print('$name is designing using $designTool');
  }
}

void main() {
  Developer developer = Developer(
    'Rahul',
    60000,
    'Dart',
  );

  Designer designer = Designer(
    'Priya',
    55000,
    'Figma',
  );

  developer.displayDetails();
  developer.work();
  developer.writeCode();

  designer.displayDetails();
  designer.work();
}

This example combines several important concepts:

  • Inheritance
  • Constructors
  • super
  • Method overriding
  • Specialized child-class functionality
  • Code reuse

34. Inheritance vs Polymorphism

Inheritance Polymorphism
Creates a parent-child relationship between classes. Allows common types to represent different implementations.
Uses extends. Often works through inheritance, interfaces, overriding, or other common abstractions.
Focuses on reuse and specialization. Focuses on interchangeable behavior.
Example: Dog extends Animal Example: Animal animal = Dog()

35. Inheritance Revision Table

Concept Purpose Example
Parent Class Provides common members. class Animal
Child Class Inherits and extends parent behavior. class Dog extends Animal
extends Creates class inheritance. class Dog extends Animal
super Accesses superclass constructors or members. super(name)
@override Marks an inherited member that is being reimplemented. @override
Single Inheritance One child directly extends one parent. Animal → Dog
Multilevel Inheritance Inheritance across multiple levels. Animal → Mammal → Dog
Hierarchical Inheritance Multiple children extend one parent. Animal → Dog, Cat, Cow

36. Practice Exercises

  1. Create an Animal parent class and a Dog child class.
  2. Add common properties such as name and age to the parent class.
  3. Create a method called sound() in the parent class.
  4. Override sound() in the child class.
  5. Create a Vehicle class and extend it using Car and Bike.
  6. Create a multilevel inheritance example using Person, Employee, and Developer.
  7. Create an e-commerce system using Product and ElectronicsProduct.
  8. Create a BankAccount parent class and a SavingsAccount child class.
  9. Create an abstract Shape class and implement it using Circle and Rectangle.
  10. Create a Flutter widget by extending StatelessWidget and overriding build().

37. Key Takeaways

  • Inheritance allows one class to reuse and extend another class.
  • The parent class is also called the superclass.
  • The child class is also called the subclass.
  • The extends keyword is used for class inheritance in Dart.
  • Constructors are not inherited.
  • The super keyword can call a parent constructor or member.
  • Child classes can add their own properties and methods.
  • Child classes can override inherited methods.
  • The @override annotation makes overriding explicit and helps tooling detect mistakes.
  • Inheritance can support polymorphism.
  • Dart does not support extending multiple classes directly.
  • Mixins, interfaces, and composition provide other ways to share behavior or abstractions.
  • Inheritance should be used when there is a meaningful subtype relationship.
  • Inheritance is an important OOP concept for understanding Dart and Flutter code.

38. JustAcademy Flutter Learning Resources

JustAcademy's Flutter course curriculum explicitly places inheritance under Dart Programming Fundamentals alongside OOP, classes, objects, constructors, polymorphism, and abstraction. :contentReference[oaicite:1]{index=1}

Flutter Training Course:
https://www.justacademy.co/course-detail/flutter-training

Register for Course Demo:
https://www.justacademy.co/register-for-course-demo

whatsapp