skip to content

In Dart, what makes a class abstract, how do you declare an abstract member, and what must a concrete subclass do with it?

level: juniorimportance: should knowfreq 60%

answer

  1. the abstract modifier on the class
  2. a signature ending in a semicolon
  3. cannot be constructed anywhere
  4. concrete subclass implements every one
  5. abstract fields exist too

basics

~20 s

A class marked abstract cannot be instantiated and may declare members with no body, written as a signature ending in a semicolon. A concrete subclass must implement every inherited abstract member, or be declared abstract itself.

solid answer

~40 s

An `abstract class` is a partial implementation: it can mix concrete members with **abstract** ones, and it can never be constructed, from any library. An abstract method, getter or setter is written as a signature ending in `;`, like `double get area;` — there is no `abstract` keyword on methods. Abstract members may only appear in abstract classes and mixins. A concrete class that extends it must supply every abstract member it inherits, otherwise the analyzer reports missing concrete implementations; declaring the subclass abstract postpones the obligation. Abstract classes can still have constructors for subclasses to call, and a factory constructor can make the type *look* instantiable by returning a concrete subtype. `super.area` on a member that is abstract in the superclass is an error.

go deeper

for a junior

Recall that abstract classes cannot be constructed and that abstract members are signatures ending in a semicolon.

for a middle

Explain the subclass obligation, abstract fields, why super calls to abstract members fail, and how a factory can return a concrete subtype.

for a senior

Use abstract members to turn missing behaviour into compile errors instead of runtime UnimplementedError, and keep shared logic in the base.

for a principal

Decide which abstractions carry shared implementation and which are pure contracts, since each commits future maintainers differently.

## Abstract classes An **abstract class** is declared with the `abstract` modifier. It describes a family of types and may provide part of their behaviour, but it is **never instantiated directly** — not from another library, and not from its own library either (`instantiate_abstract_class`). ```dart abstract class Shape { Shape(this.label); final String label; double get area; // abstract getter double get perimeter; // abstract getter Shape scaled(double k); // abstract method String describe() => // concrete method '$label: ${area.toStringAsFixed(2)} m2, perimeter ${perimeter.toStringAsFixed(2)} m'; } ``` An abstract class still has constructors. They cannot be called with `Shape(...)`, but a subclass calls them through `super(...)` to initialise the fields the abstract class owns, such as `label`. ## Declaring abstract members - **Methods, getters and setters** become abstract by ending the declaration with `;` instead of a body: `void recalc();`, `double get area;`, `set area(double v);`. - There is **no `abstract` keyword on methods**; `abstract void recalc();` is an error (`abstract_class_member`). - **Fields** are the exception: `abstract double width;` declares an abstract getter and setter pair. Abstract fields cannot have initializers or be `late`. - Abstract members can only exist in **abstract classes** (or mixins). A concrete class with a body-less method is `concrete_class_with_abstract_member`. ## Obligations of a concrete subclass ```dart class Rect extends Shape { Rect(this.width, this.height) : super('rect'); final double width, height; @override double get area => width * height; @override double get perimeter => 2 * (width + height); @override Rect scaled(double k) => Rect(width * k, height * k); } ``` 1. A **concrete** class must have an implementation for every abstract member it inherits — declared itself or inherited from further up (or supplied by a mixin). Otherwise: `non_abstract_class_inherits_abstract_member`. 2. A subclass that cannot supply them all can be declared **`abstract`** itself. 3. Inside an override, `super.area` is only valid if some superclass provides a **concrete** `area`; calling an always-abstract member via `super` is `abstract_super_member_reference`. 4. The override may **narrow the return type**: `Rect scaled(...)` legally overrides `Shape scaled(...)`. ## Looking instantiable: factory constructors An abstract class may declare a **factory constructor** that returns a concrete subtype, so callers write `Shape.square(3)` and never see the implementation class: ```dart abstract class Shape { // ... factory Shape.square(double side) = Square; } ``` ## Abstract class or plain class as interface? | Need | Choose | |---|---| | Shared code plus required hooks | abstract class, subclasses `extend` it | | Only a contract, no shared code | abstract class with only abstract members, implementers `implement` it | | Prevent direct construction | abstract class | | A usable default implementation | a concrete class | In the floor-plan calculator, `Shape` owns the reusable `describe()` and forces each concrete shape to answer `area` and `perimeter`. Code that sums a floor plan depends only on `Shape`. ## Common mistakes - Writing a method with an empty body `{}` and calling it abstract: it is concrete, and subclasses are no longer forced to override it. - Using `throw UnimplementedError()` as a body to fake abstraction: the error moves from compile time to runtime. - Expecting `Shape()` to work inside the declaring library.

  • In Dart, why write `double get area;` rather than `double get area => throw UnimplementedError();` in a base class?
    The abstract form makes the analyzer require every concrete subclass to implement `area`, so a forgotten override is a compile error. The throwing body is a concrete implementation: subclasses compile without overriding it, and the mistake only appears when `area` is read at runtime.
  • In Dart, what does `abstract double width;` declare in an abstract class?
    An abstract getter and setter pair named `width`, with no storage. Concrete subclasses must provide both, typically with an ordinary non-final field, or with an explicit getter and setter. Abstract fields cannot have an initializer and cannot be `late`.

saying these in an interview costs you the question

  • An abstract class can be instantiated from inside its own library
  • Abstract methods are declared with the abstract keyword before the return type
  • An empty method body {} makes a method abstract
  • A concrete subclass may leave inherited abstract members unimplemented and fail at runtime
  • Abstract classes cannot declare constructors