Classes and inheritance
Learning objectives
- You practice working with classes and objects in Dart.
- You know how to inherit classes in Dart.
Recapping classes and objects
We briefly looked into classes and objects previously. Classes are in essence structures that can be used to combine concepts related to the same topic and to create functionality for that topic. Objects are instances of particular classes where each object can have own values for the objects.
The following example that uses the previously defined class Task
demonstrates the use of objects and classes.
Inheritance
One of the key concepts in object-oriented programming is inheritance which means defining a new class based on another class. When a class is defined using inheritance, it inherits properties and methods of the inherited class.
Inheriting a class happens using the keyword extends
(Like in e.g. Java). The following example shows a class A
, which is then inherited by a class AB
. Note that the class A
has a property a
and the class AB
has the property b
. Because the class AB
inherits the class A
, it also has the property a
.
In inheritance-related terminology, the class that is being inherited is a parent class, while the class that inherits is a child class.
Inheritance and constructors
In Dart, classes do not inherit constructors from their parent classes. This means that constructors defined in the parent class need to be called if they are to be used. For example, the following example does not work -- when trying out code, we see an error stating that the superclass doesn't have a zero argument constructor.
Using a constructor in parent class
Properties, methods, and constructors defined in the parent class can be accessed using the keyword super
. The example below shows how to call the constructor of the parent class.
Default constructor
Note that if the parent class has a default (zero argument) constructor, it does not explicitly have to be called as it is called by default. This is demonstrated in the example below.
Inherited task example
Let's look at inheritance through the class Task
that we have previously worked with.
class Task {
String name;
bool completed = false;
Task(this.name, this.completed);
Task.completed({required this.name}) : completed = true;
Task.homework() : name = "Finish homework";
Task.fromMap(Map data)
: name = data["name"],
completed = data["completed"];
String toString() {
return "[${completed ? "x" : " "}] $name";
}
}
The class Task
does not have a default zero-argument constructor and thus any class that inherits it must call the parent constructors as well.
Let's create a class called PriorityTask
. The class PriorityTask
has a number indicating the priority of the task.
class PriorityTask {
int priority = 0;
}
To inherit the functionality from Task
, we need to extend the Task
class.
class PriorityTask extends Task {
int priority = 0;
}
The above example does not work as we are not defining a constructor. Let's define a constructor that takes two parameters: the name of the task and the priority of the task. The constructor then calls a constructor from the parent class, setting the name as the one received and setting the task as not completed. In addition, the constructor sets the priority.
class PriorityTask extends Task {
int priority = 0;
PriorityTask(String name, this.priority): super(name, false);
}
Now, we could create tasks with different priorities.