Polymorphism Basics
Part of the Object Oriented Programming section of Coddy's Dart journey — lesson 57 of 110.
Polymorphism means "many forms" - it's the ability to treat objects of different classes through a common interface. When you have a parent class reference, it can point to any child class object, and the correct method gets called based on the actual object type.
This is powerful because you can write code that works with the parent type, yet it automatically handles all child types correctly:
class Animal {
void speak() => print('Some sound');
}
class Dog extends Animal {
@override
void speak() => print('Woof!');
}
class Cat extends Animal {
@override
void speak() => print('Meow!');
}
void main() {
Animal myPet = Dog(); // Parent type, child object
myPet.speak(); // Output: Woof!
myPet = Cat(); // Same variable, different object
myPet.speak(); // Output: Meow!
}The variable myPet is declared as Animal, but it holds a Dog or Cat. When speak() is called, Dart looks at the actual object type at runtime and calls the appropriate overridden method.
This enables you to write flexible functions that work with any subclass:
void makeAllSpeak(List<Animal> animals) {
for (var animal in animals) {
animal.speak(); // Each animal speaks in its own way
}
}
void main() {
var pets = [Dog(), Cat(), Dog()];
makeAllSpeak(pets);
// Output: Woof! Meow! Woof!
}The function doesn't need to know about Dog or Cat - it just works with Animal. This makes your code more extensible since adding new animal types requires no changes to existing functions.
Challenge
EasyLet's build a musical instrument system that demonstrates polymorphism in action. You'll create a base Instrument class and several instrument types, then write a function that can make any collection of instruments play together - without knowing their specific types.
You'll organize your code into two files:
instruments.dart: Define your instrument hierarchy here:- An
Instrumentclass with aString nameproperty and a constructor. Include a methodplay()that prints[name] makes a sound - A
Guitarclass that extendsInstrumentand overridesplay()to print[name] strums melodically - A
Drumclass that extendsInstrumentand overridesplay()to print[name] beats rhythmically - A
Pianoclass that extendsInstrumentand overridesplay()to print[name] plays harmoniously
performConcert(List<Instrument> instruments)that printsConcert begins!, then iterates through the list callingplay()on each instrument, and finally printsConcert ends!- An
main.dart: Import your instruments file and demonstrate polymorphism by creating a mixed band:- Create a list of type
List<Instrument>containing aGuitarnamed'Acoustic', aDrumnamed'Snare', and aPianonamed'Grand' - Pass this list to
performConcert()
- Create a list of type
Notice how performConcert() works with the parent type Instrument, yet each instrument plays in its own unique way. This is polymorphism - the same method call produces different behavior based on the actual object type.
Expected output:
Concert begins!
Acoustic strums melodically
Snare beats rhythmically
Grand plays harmoniously
Concert ends!Cheat sheet
Polymorphism means "many forms" - it allows you to treat objects of different classes through a common interface. A parent class reference can point to any child class object, and the correct method gets called based on the actual object type at runtime.
Basic polymorphism example:
class Animal {
void speak() => print('Some sound');
}
class Dog extends Animal {
@override
void speak() => print('Woof!');
}
class Cat extends Animal {
@override
void speak() => print('Meow!');
}
void main() {
Animal myPet = Dog(); // Parent type, child object
myPet.speak(); // Output: Woof!
myPet = Cat(); // Same variable, different object
myPet.speak(); // Output: Meow!
}Polymorphism enables flexible functions that work with any subclass:
void makeAllSpeak(List<Animal> animals) {
for (var animal in animals) {
animal.speak(); // Each animal speaks in its own way
}
}
void main() {
var pets = [Dog(), Cat(), Dog()];
makeAllSpeak(pets);
// Output: Woof! Meow! Woof!
}The function works with the parent type Animal without needing to know about specific child classes like Dog or Cat. This makes code more extensible - adding new types requires no changes to existing functions.
Try it yourself
import 'instruments.dart';
void main() {
// TODO: Create a List<Instrument> containing:
// - A Guitar named 'Acoustic'
// - A Drum named 'Snare'
// - A Piano named 'Grand'
// TODO: Call performConcert() with your list of instruments
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesLibraries & ImportsIntroduction to OOPClasses vs ObjectsThe this KeywordMethodsInstance VariablesConstructor BasicsRecap - Simple Calculator4Null Safety
Intro to Null SafetyNullable vs Non-NullableThe ? and ! OperatorsLate Keyword & Null SafetyNull-Aware OperatorsNull Safety in ClassesRecap - User Profile System7Abstract Classes & Interfaces
Abstract ClassesAbstract MethodsInterfaces in DartImplicit InterfacesImplementing vs ExtendingMultiple InterfacesRecap - Shape Calculator10Collections & Generics
List, Set, Map OverviewType-Safe CollectionsGeneric ClassesGeneric MethodsGeneric ConstraintsIterable & IteratorRecap - Generic Storage13Advanced OOP Concepts
Composition vs InheritanceExtension MethodsCallable ClassesSealed Classes (Dart 3)Records (Dart 3)Patterns & Matching (3.0)Enums with Methods16Project: Library Management
Project OverviewBook and User Classes2Constructors in Dart
Default ConstructorNamed ConstructorsInitializer ListsConstant ConstructorsFactory ConstructorsRedirecting ConstructorsRecap - Shape Builder5Encapsulation
Public vs Private MembersThe _ Prefix ConventionLibrary-Level PrivacyGetters & Setters DepthInformation HidingRecap - Student Records8Mixins
Introduction to MixinsCreating MixinsUsing Multiple Mixinson Keyword in MixinsMixin vs InheritanceMixin vs InterfaceRecap - Animal System11Special Methods
toString() OverridehashCode & == OverrideComparable Interfacecall() MethodnoSuchMethod OverrideRecap - Custom Collection14Design Patterns Part 1
Intro to Design PatternsSingleton PatternFactory PatternObserver PatternStrategy Pattern3Class Properties
Instance vs Static MembersFinal & Const FieldsLate VariablesStatic Methods & FieldsGetters and SettersRecap - Bank Account Manager6Inheritance
Basic InheritanceThe super KeywordMethod OverridingThe @override AnnotationThe final Class KeywordConstructors & InheritanceRecap - Employee Hierarchy9Polymorphism
Polymorphism BasicsPolymorphism via InterfacesRuntime Type CheckingThe is & as OperatorsCovariant KeywordRecap - Payment Processor