Inheritance in Dart – Dart Object Oriented Programming (OOP) Guide

Haris Bin Nasir Avatar

·

·

Inheritance is one of the core principles of Object-Oriented Programming (OOP) that allows a class to inherit properties and methods from another class. In Dart, inheritance helps to promote code reuse and establishes relationships between classes, making the code more maintainable and structured. This post will explore inheritance in Dart, how it works, and its practical uses with examples.

For further information on other topics of Dart, click here.

For an in-depth exploration of other OOP topics in Dart, such as inheritance, polymorphism, and encapsulation etc, click here.

What is Inheritance?

Inheritance in Dart allows one class (called the subclass or child class) to inherit the properties and methods of another class (called the superclass or parent class). This provides a way to create a hierarchy of classes, where the child class extends the functionality of the parent class without rewriting code.

Key Concepts of Inheritance in Dart:

  1. Superclass: The class that is being inherited from.
  2. Subclass: The class that inherits from the superclass.
  3. Method Overriding: Allows a subclass to provide a specific implementation of a method that is already defined in the superclass.

Basic Inheritance

In Dart, inheritance is implemented using the extends keyword. When a class extends another class, it inherits all non-private members (properties and methods) of the superclass.

Example of Inheritance
class Animal {
  void eat() {
    print("Animal is eating");
  }
}

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

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

Explanation:

In this example, the Dog class inherits the eat() method from the Animal class. Additionally, Dog defines its own method, bark(). This demonstrates the basic idea of inheritance: reusing code from the parent class while adding specific functionality in the child class.

Method Overriding

In Dart, a subclass can override a method of the superclass. This is useful when the subclass needs to provide a specific implementation of a method that is already defined in the superclass.

Example of Method Overriding
class Animal {
  void sound() {
    print("Animal makes a sound");
  }
}

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

void main() {
  var cat = Cat();
  cat.sound(); // Output: Cat meows
}

Explanation:

In this example, the Cat class overrides the sound() method of the Animal class using the @override annotation. Although the Animal class has a sound() method, the Cat class provides its own implementation.

super Keyword

The super keyword in Dart is used to refer to the superclass and its members. It allows the child class to call the parent class’s constructor, methods, or properties.

Example of super Keyword
class Vehicle {
  void start() {
    print("Vehicle started");
  }
}

class Car extends Vehicle {
  @override
  void start() {
    super.start();  // Calls the start method of Vehicle
    print("Car started");
  }
}

void main() {
  var car = Car();
  car.start();  
  // Output:
  // Vehicle started
  // Car started
}

Explanation:

In the Car class, the start() method first calls the start() method of the Vehicle class using super.start(), and then it adds its own implementation. This is a great way to extend the functionality of a parent class method.

Constructors and Inheritance

When a subclass is instantiated, the constructor of the superclass is automatically called before the constructor of the subclass. You can explicitly call a superclass constructor using super() in the subclass’s constructor.

Example of Constructor Inheritance
class Person {
  String name;
  Person(this.name);

  void introduce() {
    print("Hi, my name is $name");
  }
}

class Employee extends Person {
  String company;

  Employee(String name, this.company) : super(name);  // Calls the Person constructor

  @override
  void introduce() {
    super.introduce();  // Calls the Person's introduce method
    print("I work at $company");
  }
}

void main() {
  var emp = Employee("John", "Google");
  emp.introduce();
  // Output:
  // Hi, my name is John
  // I work at Google
}

Explanation:

In this example, the Employee class inherits from the Person class. The Employee constructor explicitly calls the Person constructor using super(name). Additionally, the introduce() method of the Employee class overrides the one in Person but still calls the superclass version using super.introduce().

Inheritance and Private Variables

In Dart, private variables (those prefixed with an underscore _) in a class are not inherited by subclasses. This ensures encapsulation of private data. Subclasses cannot directly access private members of their parent classes.

Example of Inheritance and Private Variables
class Parent {
  String _secret = "This is private";

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

class Child extends Parent {
  void display() {
    // print(_secret);  // Error: '_secret' is private and cannot be accessed
    print("Trying to access private data");
  }
}

void main() {
  var child = Child();
  child.display(); // Output: Trying to access private data
}

Explanation:

In this case, the _secret variable is private to the Parent class, and the Child class cannot directly access it. This preserves encapsulation even in an inheritance hierarchy.

Multiple Inheritance in Dart

Dart does not support multiple inheritance, meaning a class cannot inherit from more than one class. However, Dart supports a feature called Mixins, which allows you to reuse code from multiple sources.

Example of Multiple Inheritance Using Mixins
mixin CanFly {
  void fly() {
    print("Flying...");
  }
}

class Bird with CanFly {}

void main() {
  var bird = Bird();
  bird.fly();  // Output: Flying...
}

Explanation:

Mixins allow a class like Bird to use code from multiple sources, simulating the effect of multiple inheritance. In this example, Bird can “inherit” the fly() method from the CanFly mixin.

Best Practices for Inheritance in Dart

  1. Use Inheritance Wisely: Inheritance is a powerful tool, but it should be used when a true “is-a” relationship exists between the parent and child classes. For example, a Dog is an Animal, but a Car is not a Vehicle in every case.
  2. Avoid Deep Inheritance Chains: Having deep chains of inheritance can make the code difficult to maintain and understand. It’s better to keep inheritance hierarchies shallow.
  3. Leverage Composition Over Inheritance: In some cases, using composition (where objects are composed of other objects) can be more flexible than inheritance.

Conclusion

Inheritance is a fundamental concept in Dart‘s OOP structure, allowing classes to reuse code and share functionality. By using inheritance, method overriding, the super keyword, and constructors, you can create structured and maintainable Dart applications. Additionally, understanding when to use inheritance and when to avoid it is key to writing clean, efficient code. For more advanced concepts and detailed explanations, be sure to check out our further articles on Dart OOP.

Happy Coding…!!!

Leave a Reply

Your email address will not be published. Required fields are marked *