Abstract classes in Dart are a fundamental concept in object-oriented programming that allow you to define a class that cannot be instantiated directly. Instead, abstract classes are meant to be subclassed, and they can contain abstract methods that must be implemented by subclasses. This is useful for defining a common interface for a group of related classes.
Key Concepts
- Abstract Class: A class that cannot be instantiated and is intended to be subclassed.
 - Abstract Method: A method that is declared without an implementation and must be overridden in a subclass.
 - Subclassing: Creating a new class that inherits from an abstract class and provides implementations for its abstract methods.
 
Defining an Abstract Class
To define an abstract class in Dart, use the abstract keyword before the class declaration. Abstract methods are declared without a body.
In this example, Animal is an abstract class with an abstract method makeSound.
Implementing Abstract Methods
A subclass must provide implementations for all abstract methods of its superclass.
class Dog extends Animal {
  @override
  void makeSound() {
    print('Bark');
  }
}
class Cat extends Animal {
  @override
  void makeSound() {
    print('Meow');
  }
}Here, Dog and Cat are subclasses of Animal and they provide their own implementations of the makeSound method.
Practical Example
Let's create a more detailed example to illustrate the use of abstract classes and methods.
Step 1: Define the Abstract Class
abstract class Shape {
  double getArea(); // Abstract method
  double getPerimeter(); // Abstract method
}Step 2: Create Subclasses
class Circle extends Shape {
  double radius;
  Circle(this.radius);
  @override
  double getArea() {
    return 3.14 * radius * radius;
  }
  @override
  double getPerimeter() {
    return 2 * 3.14 * radius;
  }
}
class Rectangle extends Shape {
  double width;
  double height;
  Rectangle(this.width, this.height);
  @override
  double getArea() {
    return width * height;
  }
  @override
  double getPerimeter() {
    return 2 * (width + height);
  }
}Step 3: Use the Subclasses
void main() {
  Shape circle = Circle(5);
  print('Circle Area: ${circle.getArea()}');
  print('Circle Perimeter: ${circle.getPerimeter()}');
  Shape rectangle = Rectangle(4, 6);
  print('Rectangle Area: ${rectangle.getArea()}');
  print('Rectangle Perimeter: ${rectangle.getPerimeter()}');
}Practical Exercises
Exercise 1: Define and Implement Abstract Class
- Define an abstract class 
Vehiclewith abstract methodsstartEngineandstopEngine. - Create two subclasses 
CarandBikethat implement theVehicleclass. - Implement the 
startEngineandstopEnginemethods in both subclasses. 
Solution
abstract class Vehicle {
  void startEngine();
  void stopEngine();
}
class Car extends Vehicle {
  @override
  void startEngine() {
    print('Car engine started');
  }
  @override
  void stopEngine() {
    print('Car engine stopped');
  }
}
class Bike extends Vehicle {
  @override
  void startEngine() {
    print('Bike engine started');
  }
  @override
  void stopEngine() {
    print('Bike engine stopped');
  }
}
void main() {
  Vehicle car = Car();
  car.startEngine();
  car.stopEngine();
  Vehicle bike = Bike();
  bike.startEngine();
  bike.stopEngine();
}Exercise 2: Extend the Shape Example
- Add a new subclass 
Squareto theShapeabstract class. - Implement the 
getAreaandgetPerimetermethods for theSquareclass. 
Solution
class Square extends Shape {
  double side;
  Square(this.side);
  @override
  double getArea() {
    return side * side;
  }
  @override
  double getPerimeter() {
    return 4 * side;
  }
}
void main() {
  Shape square = Square(4);
  print('Square Area: ${square.getArea()}');
  print('Square Perimeter: ${square.getPerimeter()}');
}Common Mistakes and Tips
- Forgetting to Override Abstract Methods: Ensure that all abstract methods in the abstract class are overridden in the subclass.
 - Instantiating Abstract Classes: Remember that you cannot create an instance of an abstract class directly.
 - Using Abstract Classes for Interfaces: Abstract classes are useful for defining interfaces that multiple classes can implement.
 
Conclusion
Abstract classes in Dart provide a powerful way to define common interfaces and enforce a contract for subclasses. By using abstract classes and methods, you can create a more organized and maintainable codebase. In the next section, we will explore interfaces in Dart, which offer another way to define contracts for classes.
Dart Programming Course
Module 1: Introduction to Dart
- Introduction to Dart
 - Setting Up the Development Environment
 - Your First Dart Program
 - Basic Syntax and Structure
 
