Welcome back to our exploration of Object-Oriented Programming (OOP) in Dart. In this session, we'll delve into Inheritance, a core concept that elevates code reusability and efficiency.
Inheritance in Object-Oriented Programming (OOP) allows a new class, known as the Child class, to inherit properties and methods from another class, termed the Parent class. This principle not only facilitates code reusability but also organizes classes into a hierarchical structure.
To understand inheritance better, we're going to dive into a practical example where we use Vehicle
as the parent class and Car
as the child class. This will help us see how child classes can adopt attributes and behaviors from parent classes, while also introducing or modifying features to meet their specific needs. In Dart, the relationship between parent and child classes is established using the extends
keyword.
We begin by defining a Vehicle
class that includes common properties and methods applicable to all types of vehicles.
Dart1// Vehicle class - Parent class 2class Vehicle { 3 String name; // Vehicle name 4 double speed; // Maximum speed 5 6 // Constructor 7 Vehicle(this.name, this.speed) { 8 print('Calling Vehicle constructor'); 9 } 10 11 void move() { 12 print('$name moves at $speed mph.'); 13 } 14}
Next, we extend the Vehicle
class to create a Car
class. The Car
class inherits properties from Vehicle
and adds a specific characteristic, the number of wheels.
Dart1// 'Car' class extending 'Vehicle' - Child class 2class Car extends Vehicle { 3 int wheels; // Additional property unique to Car 4 5 Car(String name, double speed, this.wheels) : super(name, speed); // Calling Vehicle's constructor 6 7 void specs() { 8 print('I am a $name and I have $wheels wheels.'); 9 } 10}
Following the demonstration of the Car
class, you might have noticed two pivotal keywords in action: extends
and super
.
extends
Keyword:
Car
) that inherits properties and methods from a superclass (e.g., Vehicle
), the extends
keyword streamlines code reuse and maintenance. It signifies that Car
is a specialized version of Vehicle
.super
Keyword:
super
keyword in the subclass constructor calls the superclass's constructor, ensuring inherited properties (like name
and speed
from Vehicle
) are initialized properly. This maintains the integrity of the inherited properties during object creation.In essence, extends
lets a subclass inherit from a superclass, while super
initializes inherited properties correctly, facilitating effective code reuse and organization in Dart programs.
Now in the main function, let’s instantiate a Car
object and observe how it utilizes both inherited methods and its specialized method.
Dart1void main() { 2 Car myCar = Car('Toyota', 120.0, 4); // Output: Calling Vehicle constructor 3 // Inherited method from Vehicle 4 myCar.move(); // Output: Toyota moves at 120.0 mph. 5 // Car's own method 6 myCar.specs(); // Output: I am a Toyota and I have 4 wheels. 7}
In some scenarios, a child class may need to modify an inherited method to suit its specific requirements. Dart allows method overriding for this purpose, enabling a child class to provide a new implementation for an inherited method. This is where the @override
annotation comes into play, serving as a clear indicator that the method below it is intended to replace an inherited method with the same signature.
Example of overriding the move
method in the Car
class:
Dart1class Car extends Vehicle { 2 // Other properties and constructor 3 4 @override 5 void move() { 6 print('$name zooms at $speed mph with its $wheels wheels.'); 7 } 8}
To see the @override
feature in action, consider the following example where we instantiate a Vehicle
and a Car
and invoke their move
method:
Dart1void main() { 2 Vehicle myVehicle = Vehicle('Bicycle', 15.0); // Output: Calling Vehicle constructor 3 myVehicle.move(); // Output: Bicycle moves at 15.0 mph. 4 5 Car myCar = Car('Toyota', 120.0, 4); // Output: Calling Vehicle constructor 6 myCar.move(); // Output: Toyota zooms at 120.0 mph with its 4 wheels. 7}
In this demonstration, myVehicle.move()
invokes the original method defined in the Vehicle
class, whereas myCar.move()
invokes the overridden method in the Car
class, which includes additional information specific to cars. This ability to override methods ensures that child classes can behave in ways that are more appropriate for their context while still benefiting from methods and properties defined in their parent classes.
Today, we've dissected inheritance in Dart, by using ‘Vehicle’ and ‘Car’ classes to demonstrate inheritance in action, highlighting how child classes inherit and potentially modify properties and methods from parent classes, alonside the significance of the extends
and super
keywords in establishing and facilitating this inheritance.