Skip to main content
An abstract class is a class declared with the abstract modifier that cannot be instantiated directly. It serves as a structural template, defining a contract through abstract members while optionally providing concrete implementation logic for subclasses to inherit.

Declaration Syntax

To define an abstract class, precede the class keyword with abstract.
abstract class AbstractContainer {
  // Class members go here
}

Instantiation Restrictions

Attempting to create an instance of an abstract class using a generative constructor results in a compile-time error.
void main() {
  // Error: The class 'AbstractContainer' is abstract and can't be instantiated.
  var container = AbstractContainer(); 
}

Abstract Methods

Abstract classes may contain abstract methods. These are methods declared with a signature and return type but without a method body. Instead of curly braces {}, the declaration terminates with a semicolon ;. Concrete subclasses extending the abstract class are strictly required to provide implementations for all abstract methods.
abstract class DatabaseConnector {
  // Abstract method: No body, ends with semicolon
  void connect(String uri);
  
  // Abstract getter
  bool get isConnected;
}

Concrete Members

Abstract classes may also contain fully implemented methods, getters, setters, and fields. Subclasses inherit these members and can override them if necessary, but they are not required to do so unless the member is abstract.
abstract class Logger {
  // Concrete method
  void log(String message) {
    print('Log: $message');
  }
  
  // Abstract method
  void saveLog();
}

Inheritance and Implementation

Dart distinguishes between extending an abstract class and implementing it as an interface.

1. Extending (extends)

When using extends, the subclass inherits the concrete implementation and must override only the abstract members.
class FileLogger extends Logger {
  @override
  void saveLog() {
    // Must implement abstract method
  }
  // 'log' method is inherited automatically
}

2. Implementing (implements)

Dart classes are implicit interfaces. When using implements, the subclass treats the abstract class purely as an interface. The subclass must override every member (abstract and concrete) and does not inherit any implementation logic.
class NetworkLogger implements Logger {
  @override
  void log(String message) {
    // Must re-implement concrete method
  }

  @override
  void saveLog() {
    // Must implement abstract method
  }
}

Constructors

Abstract classes can define constructors. While these cannot be called to instantiate the abstract class directly, they are invoked by subclasses using super() to initialize state defined in the abstract base.
abstract class Entity {
  final String id;

  // Constructor
  Entity(this.id);
}

class User extends Entity {
  String name;

  // Calls the abstract class constructor
  User(String id, this.name) : super(id);
}

Factory Constructors

An abstract class can appear to be instantiated if it defines a factory constructor that returns an instance of a concrete subclass.
abstract class Shape {
  factory Shape(String type) {
    if (type == 'circle') return Circle();
    throw UnimplementedError();
  }
  
  void draw();
}

class Circle implements Shape {
  @override
  void draw() => print("Drawing Circle");
}

void main() {
  // Valid: Calls the factory constructor, which returns a Circle
  var s = Shape('circle'); 
}
Master Dart with Deep Grasping Methodology!Learn More