# Inheritance

Course: [Dart](https://www.devtutorials.ai/learn/dart) · Section: Object-Oriented Programming
Source: https://www.devtutorials.ai/learn/dart/object-oriented/inheritance

> How to build a child class on a parent with extends, override and use super, and when to build objects from parts instead, with aggregation and composition.

## What Is Inheritance?

**Inheritance** = making a new class **from** an existing class. The new class gets everything the old one has, and adds more.

- **Parent class** (superclass) = the class you start from.
- **Child class** (subclass) = the new class built on top of it.
- The child **inherits** the parent's fields and methods.
- An "**is-a**" test tells you when to use it: a Student **is a** Person.

**Simple lesson:** inheritance lets you write shared code once, in the parent, and reuse it in every child.

### A Real-World Example

Everyone in Green Valley School is a **person** with a name.

- A **student** is a person who also has a roll number.
- A **teacher** is a person who also has a subject.
- A **class monitor** is a student who also has a duty.
- Writing `name` and `greet()` again in every class would be a waste. The parent holds them once.

Click a class to see what it owns and what it inherits:

Every **Run** box on this page runs on the course's Dart runner in your browser.

In Dart, every class you write already has a parent: `Object`. That is where `toString()` and `hashCode` come from.

## What You Will Learn

In this lesson, you will learn:

1. How to create a child class with `extends`, and the kinds of inheritance.
2. How to override methods and use `super`.
3. What has-a relationships are.
4. Aggregation and composition, and how they differ.
5. When to choose composition over inheritance.

## The extends Keyword

### Creating a Child Class

```text
class Child extends Parent { ... }
```

```dart runnable title="A Student is a Person"
class Person {
  String name;
  Person(this.name);

  void greet() => print('Hello, I am $name.');
}

class Student extends Person {
  int rollNo;
  Student(String name, this.rollNo) : super(name);

  void study() => print('$name (roll $rollNo) is studying.');
}

void main() {
  var s = Student('Asha', 12);
  s.greet();
  s.study();
  print(s.name);
}
```

- `Student` never wrote `greet()` or `name`, but it has both.
- `: super(name)` passes `name` up to the `Person` constructor. More on this below.

### Inherited Fields and Methods

What a child gets from its parent:

| Gets | Example |
|---|---|
| Public fields | `name` |
| Public methods | `greet()` |
| Getters and setters | `get initials` |
| Private `_` members, if in the same file | `_secret` |

What a child does **not** get:

- **Constructors.** Each class writes its own, and calls the parent's with `super`.
- **Static members.** Use them with the parent's name: `Person.count`.

**Simple lesson:** `extends` copies the parent's abilities into the child, except constructors and statics.

## Types of Inheritance

### Single, Multi-Level and Hierarchical

| Type | Shape | Example |
|---|---|---|
| **Single** | one parent, one child | `Person` → `Student` |
| **Multi-level** | a chain | `Person` → `Student` → `Monitor` |
| **Hierarchical** | one parent, many children | `Person` → `Student` and `Person` → `Teacher` |

```dart runnable title="Multi-level and hierarchical together"
class Person {
  String name;
  Person(this.name);
  void greet() => print('Hello, I am $name.');
}

class Student extends Person {
  Student(String name) : super(name);
  void study() => print('$name is studying.');
}

class Monitor extends Student {
  Monitor(String name) : super(name);
  void takeAttendance() => print('$name is taking attendance.');
}

class Teacher extends Person {
  Teacher(String name) : super(name);
  void teach() => print('$name is teaching.');
}

void main() {
  var m = Monitor('Kiran');
  m.greet();
  m.study();
  m.takeAttendance();
  Teacher('Mrs. Iyer').greet();
  print(m is Person);
  print(m is Teacher);
}
```

A `Monitor` has all three methods. And `m is Person` is `true`, because a monitor is a student, and a student is a person.

### Multiple Inheritance: Not in Dart

**Multiple inheritance** = one class with **two parents**: `class SportsCaptain extends Student, Athlete`.

- Dart does **not** allow this. A class has exactly **one** parent.
- Two parents could both have a `play()` method. Which one should run? Dart avoids that confusion.
- Instead, Dart gives you two tools:
  - **interfaces** with `implements` (see **Polymorphism**)
  - **mixins** with `with` (see **Mixins**)

```dart
class SportsCaptain extends Student, Athlete {}
// Error: Each class definition can have at most one extends clause.
```

**Simple lesson:** a Dart class has one parent, but that parent can have its own parent, and so on.

## Overriding Methods

### Using @override

**Override** = a child writes its **own version** of a method it inherited.

- Same name, same parameters, a new body.
- Put `@override` above it. It tells readers (and Dart) "this replaces a parent method".
- If you spell the name wrong, `@override` makes Dart warn you.

```dart runnable title="Each animal speaks its own way"
class Animal {
  String name;
  Animal(this.name);
  void speak() => print('$name makes a sound.');
}

class Dog extends Animal {
  Dog(String name) : super(name);

  @override
  void speak() => print('$name says Woof!');
}

class Cat extends Animal {
  Cat(String name) : super(name);
}

void main() {
  Dog('Tommy').speak();
  Cat('Billu').speak();
}
```

`Dog` overrides `speak()`. `Cat` does not, so it uses the parent's version.

### Overriding toString()

Every class inherits `toString()` from `Object`. Override it to print something useful:

```dart runnable title="A friendly print for a student"
class Student {
  String name;
  int marks;
  Student(this.name, this.marks);

  @override
  String toString() => 'Student($name, $marks)';
}

void main() {
  var s = Student('Ravi', 75);
  print(s);
  print([s, Student('Priya', 85)]);
}
```

`@override` is not required to make overriding work. But always write it.

It documents your intent, and it catches spelling mistakes like `toSting()`.

**Simple lesson:** override when the child must do the job differently, and mark it with `@override`.

## The super Keyword

### Calling the Parent's Method

**`super`** = "the parent's version". Use it inside a child to reach what you replaced.

- Without `super.`, calling `describe()` inside `describe()` would call **itself** forever.
- `super.` lets the child **add to** the parent's work, instead of replacing it all.

### Calling the Parent's Constructor

A child must **build its parent part first**. You pass the values with `super(...)`:

```dart runnable title="super in the initializer list"
class Person {
  String name;
  Person(this.name) {
    print('Person part built for $name');
  }
}

class Teacher extends Person {
  String subject;
  Teacher(String name, this.subject) : super(name) {
    print('Teacher part built: $subject');
  }
}

void main() {
  var t = Teacher('Mrs. Iyer', 'Science');
  print('${t.name} teaches ${t.subject}');
}
```

The parent's constructor body runs **before** the child's body.

### Super Parameters

**Super parameter** = `super.name` in the child's parameter list. It passes the value straight to the parent. Shorter, same meaning.

```dart runnable title="super.name does the passing for you"
class Person {
  final String name;
  final int age;
  Person(this.name, this.age);
}

class Student extends Person {
  final String house;
  Student(super.name, super.age, this.house);

  @override
  String toString() => '$name, $age, $house house';
}

void main() {
  print(Student('Meena', 13, 'Blue'));
}
```

| Long way | Short way |
|---|---|
| `Student(String name, int age, this.house) : super(name, age);` | `Student(super.name, super.age, this.house);` |

**Simple lesson:** `super.method()` reuses the parent's method, and `super(...)` or `super.x` builds the parent part.

## Designing Good Hierarchies

- Put **shared** fields and methods in the parent. Put **special** ones in the child.
- Keep chains short. Two or three levels is usually enough.
- Use the "**is-a**" test. A `Car` is **not** an `Engine`, so `Car extends Engine` is wrong.
- When the test is "**has-a**" (a car **has an** engine), use a field instead, as shown below.

Do not inherit just to borrow one method.

If `Library extends Student` only to reuse `printName()`, every library would also get `rollNo` and `study()`. That makes no sense.

**Easy way to remember**

- `extends` = "**is a** kind of".
- `@override` = "I do this my own way".
- `super.x()` = "do it the parent's way too".
- `super.name` in the constructor = "pass this up to the parent".

**Simple lesson:** inheritance is for real "is-a" families, kept short and simple.

## What Are Aggregation and Composition?

Both are ways to build a big object **out of** smaller objects. They are "**has-a**" relationships.

- **Has-a relationship** = one object keeps another object in a field. A school **has** classrooms.
- **Aggregation** = the parts are **shared**. They were made **outside**, and they live on if the whole goes away.
- **Composition** = the parts are **owned**. The whole **makes** them, and they go away with it.

**Simple lesson:** aggregation borrows parts, and composition owns its parts.

### A Real-World Example

Look at Green Valley School.

- The school **has** classrooms. Rooms 7A and 7B are built **inside** the school. Close the school, and the rooms are gone too. That is **composition**.
- The school **has** teachers. Mrs. Iyer was a person before she joined, and she still is if the school closes. That is **aggregation**.

Close the school and watch which parts go with it:

Dart does not have special keywords for these ideas. You show them by **where** an object is made, and **who** keeps it.

## Has-a Relationships

**Is-a** (from above) and **has-a** are different questions:

| Question | Answer | Tool |
|---|---|---|
| Is a Student a Person? | yes | `extends` |
| Does a Student **have** a Bag? | yes | a field: `Bag bag;` |
| Is a Car an Engine? | **no** | do not extend |
| Does a Car **have** an Engine? | yes | a field: `Engine engine;` |

```dart runnable title="A student has a bag"
class Bag {
  final String colour;
  final List<String> books = [];
  Bag(this.colour);
}

class Student {
  final String name;
  final Bag bag;
  Student(this.name, this.bag);

  void pack(String book) {
    bag.books.add(book);
    print('$name packed $book in the ${bag.colour} bag');
  }
}

void main() {
  var s = Student('Asha', Bag('blue'));
  s.pack('Maths');
  s.pack('Science');
  print(s.bag.books);
}
```

**Simple lesson:** if "X has a Y" sounds right, give X a field of type Y.

## Aggregation

**Aggregation** = the whole **holds a link** to parts that exist on their own.

- The parts are usually **passed in** from outside (as constructor or method arguments).
- The same part can be shared by **many** wholes.
- Removing the whole does not remove the parts.

```dart runnable title="Two clubs share the same student"
class Student {
  final String name;
  Student(this.name);
}

class Club {
  final String title;
  final List<Student> members = [];
  Club(this.title);

  void join(Student s) => members.add(s);

  void show() => print('$title: ${members.map((m) => m.name).join(', ')}');
}

void main() {
  var asha = Student('Asha');
  var ravi = Student('Ravi');

  var chess = Club('Chess')..join(asha)..join(ravi);
  var music = Club('Music')..join(asha);

  chess.show();
  music.show();

  chess.members.clear();
  print('Chess club closed. Asha is still ${asha.name}.');
  music.show();
}
```

- `asha` was made **outside** both clubs.
- Clearing the chess club did not touch her. She is still in the music club.

**Simple lesson:** in aggregation, the whole only points to parts that someone else made.

## Composition

**Composition** = the whole **creates and owns** its parts.

- The parts are made **inside** the whole, often in its constructor.
- Nobody else holds them. They are **private** to the whole.
- When the whole is gone, the parts are gone too.

```dart runnable title="A timetable owns its periods"
class Period {
  final String subject;
  final String time;
  Period(this.subject, this.time);
}

class Timetable {
  final String className;
  final List<Period> _periods = [];

  Timetable(this.className) {
    _periods.add(Period('Maths', '9:00'));
    _periods.add(Period('Science', '9:45'));
    _periods.add(Period('English', '10:30'));
  }

  void show() {
    print('Timetable for $className');
    for (var p in _periods) {
      print('  ${p.time}  ${p.subject}');
    }
  }
}

void main() {
  var t = Timetable('7A');
  t.show();
}
```

- The `Period` objects are made **inside** `Timetable`.
- `_periods` is private, so no outside code can take them away.
- A period for 7A has no meaning without 7A's timetable.

A quick test: **who called the constructor of the part?**

- The whole called it: **composition**.
- Someone else called it, and passed the part in: **aggregation**.

**Simple lesson:** in composition, the whole builds its parts and keeps them to itself.

## Comparing the Two

| | Aggregation | Composition |
|---|---|---|
| Ownership | shared, the whole only links to it | owned by the whole |
| Who makes the part? | outside code | the whole itself |
| Lifetime | the part lives on alone | the part ends with the whole |
| Shared by many wholes? | yes | no |
| School example | school **has** teachers | school **has** classrooms |
| Other example | a playlist **has** songs | a house **has** rooms |

Both in one program:

```dart runnable title="A playlist borrows songs, a house owns rooms"
class Song {
  final String title;
  Song(this.title);
}

class Playlist {
  final String name;
  final List<Song> songs;
  Playlist(this.name, this.songs);
}

class Room {
  final String use;
  Room(this.use);
}

class House {
  final List<Room> _rooms = [Room('kitchen'), Room('bedroom')];
  int get roomCount => _rooms.length;
}

void main() {
  var anthem = Song('Jana Gana Mana');
  var morning = Playlist('Assembly', [anthem]);
  var sports = Playlist('Sports Day', [anthem]);
  print('${morning.name} and ${sports.name} share ${anthem.title}');

  var home = House();
  print('The house made its own ${home.roomCount} rooms');
}
```

**Simple lesson:** ask "can the part live alone?". Yes means aggregation. No means composition.

## Inheritance or Composition?

Sometimes both could work. Which is better?

```dart runnable title="A phone built from parts, not from a parent"
class Camera {
  void click() => print('Photo taken');
}

class Speaker {
  void play(String song) => print('Playing $song');
}

class Phone {
  final Camera _camera = Camera();
  final Speaker _speaker = Speaker();

  void takePhoto() => _camera.click();
  void playSong(String song) => _speaker.play(song);
}

void main() {
  var p = Phone();
  p.takePhoto();
  p.playSong('Jana Gana Mana');
}
```

- A phone is **not a** camera. It **has** a camera. So composition fits.
- With `extends`, a phone could only have **one** parent. With fields, it can have **many** parts.
- Each part can be changed or tested on its own.

| Choose | When |
|---|---|
| **Inheritance** (`extends`) | a true "is-a", and the child really is a special kind of the parent |
| **Composition** (fields) | a "has-a", or you want to mix many abilities |

A common beginner mistake is `class Phone extends Camera`. It compiles, but now a phone **is a** camera, with every camera method on it. Later changes to `Camera` can break `Phone` in surprising ways.

**Easy way to remember**

- **is-a**: inheritance.
- **has-a, borrowed**: aggregation (passed in, shared).
- **has-a, owned**: composition (made inside, private).
- When in doubt, prefer **composition**.

**Simple lesson:** prefer building from parts, and use inheritance only for real "is-a" families.

## TL;DR

1. **`class Child extends Parent`** inherits the parent's fields and methods. One parent only.
2. **Override** with `@override`. **`super.m()`** runs the parent's version. **`super.name`** passes values up.
3. **Has-a** = one object keeps another in a field.
4. **Aggregation:** parts made outside and shared. **Composition:** parts made inside and owned.
5. Use inheritance for **is-a**, and prefer composition for **has-a**.

## Common mistakes

| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
| `class A extends B, C` | A class can have two parents | One parent only | A compile error. |
| Forgetting `: super(name)` | The parent builds itself | Pass the parent's required values | A compile error: the parent needs arguments. |
| Calling `describe()` inside `describe()` | It reaches the parent | Write `super.describe()` | It calls itself forever: Stack Overflow. |
| Leaving out `@override` | It is only decoration | It catches spelling mistakes | A typo makes a new method silently. |
| `Car extends Engine` | Inherit to reuse code | Use "is-a". A car **has** an engine | A confusing class design. |
| Expecting constructors to be inherited | Children get every member | Each class writes its own constructor | A compile error when you call it. |
| `class Car extends Engine` | Inherit to reuse | A car **has** an engine: use a field | Odd methods appear on Car. |
| A public list of owned parts | Public is simpler | Keep owned parts private: `_periods` | Outside code removes parts the whole needs. |
| Making shared parts inside the whole | Every whole needs its own copy | Pass shared parts in | Two "Ashas" that should be one person. |
| Thinking Dart has `aggregate` or `compose` keywords | They are language features | They are design ideas, built with fields | Confusion when reading code. |
| Deep `extends` chains to collect abilities | More parents, more power | Combine parts with fields | Fragile, hard-to-change code. |

## Check Yourself

## Exercises

## What to Remember

- `extends` makes a child class that reuses the parent's code.
- Override with `@override`, and reach the parent with `super`.
- A has-a relationship is a field that holds another object.
- Aggregation shares parts, and composition owns them.
- Keep inheritance for true is-a families, and build everything else from parts.

Next: **Polymorphism**. You will write plans that classes must follow, and see one call do different things for different objects.
