Dart Inheritance
Inheritance is one of the three main features of object-oriented programming. It allows a class to be based on another class for extension.
This chapter introduces Dart's extends single inheritance, method overriding, super keyword, and abstract classes.
* * *
## extends Single Inheritance
Dart only supports single inheritance β each class can have only one direct parent class.
However, the inheritance chain can be long: child class inherits from parent class, parent class inherits from grandparent class, and so on.
## Example
// Parent class (base class, superclass)
class Animal {
String name;
Animal(this.name);
void eat(){
print('$name is eating');
}
void sleep(){
print('$name is sleeping');
}
}
// Subclass: inherits from Animal using extends
class Dog extends Animal {
String breed;// Breed
// Subclass constructor needs to call parent constructor
Dog(String name,this.breed):super(name);
// New method added by subclass
void bark(){
print('$name ($breed) is barking!');
}
}
void main(){
var dog = Dog('Wangcai','Golden Retriever');
// Call methods inherited from parent class
dog.eat();
dog.sleep();
// Call subclass's own method
dog.bark();
// Subclass object is also a parent type
Animal animal = dog;// Dog is Animal, can be upcast
animal.eat();
}
Wangcai is eatingWangcai is sleepingWangcai (Golden Retriever) is barking!Wangcai is eating
Subclass can access all non-private member variables and methods in the parent class.
Private members (starting with underscore) will not be inherited.
> Dart does not have public, protected, private keywords. Members starting with underscore (_) are library-private and can only be accessed within the same file. This is different from Java/C++ access control.
* * *
## Method Overriding @override
Subclass can override (override) methods in the parent class to provide its own implementation.
Use the @override annotation to explicitly indicate the overriding intent, and the compiler will help you check if it's correctly overridden.
## Example
class Animal {
String name;
Animal(this.name);
// Parent class method
void makeSound(){
print('$name makes some sounds');
}
@override
String toString(){
return'Animal: $name';
}
}
class Cat extends Animal {
Cat(String name):super(name);
// @override annotation: tells compiler I'm overriding parent method
@override
void makeSound(){
print('$name meowsο½');
}
}
class Duck extends Animal {
Duck(String name):super(name);
@override
void makeSound(){
print('$name quacks!');
}
}
void main(){
var cat = Cat('Xiaohua');
var duck = Duck('Donald');
cat.makeSound();
duck.makeSound();
// Polymorphism: same method, different objects have different behaviors
List animals =[
Cat('Mimi'),
Duck('Yaya'),
Cat('Qiuqiu'),
];
print('--- TUTORIAL Zoo ---');
for(var animal in animals){
animal.makeSound();// At runtime, calls the actual type's method
}
}
Xiaohua meowsο½Donald quacks!--- TUTORIAL Zoo ---Mimi meowsο½Yaya quacksοΌQiuqiu meowsο½
The example above demonstrates Polymorphism: the same method call animal.makeSound(), the actual behavior executed depends on the object's real type.
> Using @override annotation has two benefits: first, it makes the code intent clearer, second, if the parent class doesn't have a method with the same name (e.g., typo), the compiler will report an error. It is recommended to always add @override.
* * *
## super Keyword
super represents the parent class object, and subclasses use super to call the parent class's constructor, methods, and properties.
## Example
class Vehicle {
String brand;
int year;
Vehicle(this.brand,this.year);
void start(){
print('$brand vehicle started');
}
void displayInfo(){
print('Brand: $brand, Year: $year');
}
}
class ElectricCar extends Vehicle {
int batteryLevel;
ElectricCar(String brand,int year,this.batteryLevel)
:super(brand, year);// Call parent class constructor
@override
void start(){
// Call parent class method in subclass method
super.start();// First execute parent class's startup logic
print('Battery level: $batteryLevel%');
print('Electric motor silent start complete');
}
@override
void displayInfo(){
super.displayInfo();// First display parent class's basic info
print('Battery level: $batteryLevel%');// Then add subclass's specific info
}
}
void main(){
var car = ElectricCar('TUTORIAL EV',2026,85);
car.start();
print('---');
car.displayInfo();
}
TUTORIAL EV vehicle startedBattery level: 85%Electric motor silent start complete---Brand: TUTORIAL EV, Year: 2026Battery level: 85%
### super Usage Scenarios Summary
| Scenario | Syntax | Description |
| --- | --- | --- |
| Call parent constructor | : super(args) | Must be called in initializer list |
| Call parent method | super.methodName() | Can be called in subclass override method |
| Access parent property | super.propertyName | Access parent class's member variable |
* * *
## Abstract Class abstract
Abstract classes are classes that cannot be directly instantiated. They only define interface specifications, and subclasses implement the specific logic.
## Example
// abstract keyword to declare abstract class
abstract class Shape {
// Abstract method: no method body, subclass must implement
double getArea();
double getPerimeter();
// Abstract class can also have concrete methods
void describe(){
print('This is a shape, area: ${getArea()}, perimeter: ${getPerimeter()}');
}
}
class Rectangle extends Shape {
double width;
double height;
Rectangle(this.width,this.height);
@override
double getArea()=> width * height;
@override
double getPerimeter()=>2*(width + height);
}
class Circle extends Shape {
double radius;
Circle(this.radius);
@override
double getArea()=>3.14159* radius * radius;
@override
double getPerimeter()=>2*3.14159* radius;
}
void main(){
// Shape shape = Shape(); // Error! Abstract class cannot be instantiated
var rect = Rectangle(10,5);
var circle = Circle(7);
rect.describe();
circle.describe();
// Use abstract class as type
List shapes =[
Rectangle(3,4),
Circle(5),
Rectangle(6,2),
];
print('--- TUTORIAL Shape Statistics ---');
double totalArea =0;
for(var shape in shapes){
totalArea += shape.getArea();
}
print('Total area: ${totalArea.toStringAsFixed(2)}');
}
This is a shape, area: 50.0, perimeter: 30.0This is a shape, area: 153.93791, perimeter: 43.
YouTip