Menu
Coddy logo textTech

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 icon

Challenge

Easy

Let'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 Instrument class with a String name property and a constructor. Include a method play() that prints [name] makes a sound
    • A Guitar class that extends Instrument and overrides play() to print [name] strums melodically
    • A Drum class that extends Instrument and overrides play() to print [name] beats rhythmically
    • A Piano class that extends Instrument and overrides play() to print [name] plays harmoniously
    Also create a function performConcert(List<Instrument> instruments) that prints Concert begins!, then iterates through the list calling play() on each instrument, and finally prints Concert ends!
  • main.dart: Import your instruments file and demonstrate polymorphism by creating a mixed band:
    • Create a list of type List<Instrument> containing a Guitar named 'Acoustic', a Drum named 'Snare', and a Piano named 'Grand'
    • Pass this list to performConcert()

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
  
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming