Class Inheritance and Member Overriding

Extend a class

Use the extends keyword to create a subclass derived from a superclass.

Use the super keyword to access members (methods, constructors, etc.) defined in the superclass from within a subclass.

class Television {
  void turnOn() {
     ...
     // Code executed inside the superclass method
  }
}

// SmartTelevision is the subclass, Television is the superclass
class SmartTelevision extends Television {
  @override
  void turnOn() {
    super.turnOn(); // Call the turnOn method from superclass
    // Unique logic for the subclass
    ...
  }
}Code language: Dart (dart)

For example, a regular television acts as the superclass, while a smart television serves as the subclass; the smart television inherits features from the basic television.

extends has another common use case: related to parameterized types covered in the generics chapter.

Practical Example
class Television {
  void turnOn() {
    print("Power on TV, output basic display signal");
  }
}

// SmartTelevision is the subclass, Television is the superclass
class SmartTelevision extends Television {
  @override
  void turnOn() {
    super.turnOn(); // Call the turnOn method from superclass
    // Unique logic for the subclass
    print("Smart TV: Activate network module, load smart system home screen");
  }
}

void main() {
  // Instance of regular television
  Television normalTv = Television();
  print("===== Normal TV Power On =====");
  normalTv.turnOn();

  // Instance of smart television
  SmartTelevision smartTv = SmartTelevision();
  print("\n===== Smart TV Power On =====");
  smartTv.turnOn();
}Code language: Dart (dart)

Execution Output

D:\dartdemo\firstdart>dart run
Building package executable... (1.4s)
Built firstdart:firstdart.
===== Normal TV Power On =====
Power on TV, output basic display signal

===== Smart TV Power On =====
Power on TV, output basic display signal

Overriding members

1. Overridable Elements

A subclass can override: instance methods (including operators), getters and setters.

2. The @override Annotation

Purpose: Explicitly mark that the method intentionally overrides a superclass member, enabling compiler validation checks.

class Television {
  set contrast(int value) {}
}

class SmartTelevision extends Television {
  @override // Informs compiler this method overrides superclass implementation
  set contrast(num value) {}
}
Code language: JavaScript (javascript)

3. Rules for Valid Overrides

  1. Return Type: The override method’s return type must match the superclass method’s return type, or be a subtype of it.
  2. Parameter Type: The override method’s parameter type must match the superclass parameter type, or be a supertype. (As shown in the example: intnum. num is a supertype of int, which is valid.)
  3. Positional Parameter Count: If the original method has n positional parameters, the overriding method must also declare exactly n positional parameters.
  4. Generic Constraints: Generic methods cannot override non-generic methods, and non-generic methods cannot override generic methods.

4. The covariant Keyword (Special Case for Type Narrowing)

Standard rules forbid narrowing parameter types (downcasting can trigger runtime type exceptions);

If developers can guarantee no runtime type errors will occur, mark parameters with covariant to enable parameter type narrowing.

When overriding the equality operator ==, you must also override the hashCode getter inherited from Object.


noSuchMethod ()

1. Purpose

When your code attempts to call a non-existent instance method / instance variable, you may override noSuchMethod() to intercept the call and implement custom handling logic.

If left unoverridden, accessing non-existent members will directly throw a NoSuchMethodError.

class A {
  @override
  void noSuchMethod(Invocation invocation) {
    print('You tried to use a non-existent member: ${invocation.memberName}');
  }
}
Code language: JavaScript (javascript)
  • Invocation object: Stores all information about the invocation (member name, arguments, etc.)
2. Two Prerequisites to Trigger noSuchMethod for Unimplemented Methods (One Must Be Met)
  1. The static type of the caller receiver is dynamic;
  2. The receiver’s static type declares the unimplemented method (it may be an abstract method), and the receiver’s runtime type provides a custom noSuchMethod() different from the built-in implementation inside Object.

Example

class A {
  @override
  void noSuchMethod(Invocation invocation) {
    print('You tried to use a non-existent member: ${invocation.memberName}');
    // Print extra invocation details to demonstrate full call information
    print('Arguments passed:${invocation.arguments}');
    print('Invocation type:${invocation.runtimeType}');
  }
}

void main() {
  A obj = A();
  // Call undefined method, triggers noSuchMethod
  obj.hello("test", 123);
  // Access undefined property
  obj.unknownValue;
}Code language: Dart (dart)
D:\dartdemo\firstdart>dart run
Building package executable...
Failed to build firstdart:firstdart:
bin/firstdart.dart:6:30: Error: The getter 'arguments' isn't defined for the type 'Invocation'.
 - 'Invocation' is from 'dart:core'.
Try correcting the name to the name of an existing getter, or defining a getter or field named 'arguments'.
    print('cal:${invocation.arguments}');
                             ^^^^^^^^^
bin/firstdart.dart:14:7: Error: The method 'hello' isn't defined for the type 'A'.
 - 'A' is from 'bin/firstdart.dart'.
Try correcting the name to the name of an existing method, or defining a method named 'hello'.
  obj.hello("test", 123);
      ^^^^^
bin/firstdart.dart:16:7: Error: The getter 'unknownValue' isn't defined for the type 'A'.
 - 'A' is from 'bin/firstdart.dart'.
Try correcting the name to the name of an existing getter, or defining a getter or field named 'unknownValue'.
  obj.unknownValue;Code language: PHP (php)

Class Inheritance and Member Overriding

Previous:
Next:

Leave a Reply

Your email address will not be published. Required fields are marked *