Overriding and Dynamic Dispatch
Overriding and Dynamic Dispatch
About
- Method Overriding: Subclass redefinition
- Dynamic Dispatch: Runtime method selection
- @override: Explicit annotation
- Performance: Virtual call overhead
Main Topics
-
Basic Overriding
-
Definition: Subclass implementation
-
Example:
class Vehicle { void move() => print('Moving'); } class Car extends Vehicle { @override void move() => print('Driving'); }
-
-
Virtual Methods
- Definition: Default in Dart
- Example:
Vehicle v = Car(); v.move(); // "Driving" (virtual call)
-
@override Annotation
- Definition: Explicit intent
- Example:
@override void dispose() { // Cleanup super.dispose(); }
-
Super Calls
- Definition: Parent implementation
- Example:
@override void initState() { super.initState(); // Additional setup }
-
Performance Considerations
- Definition: Virtual call costs
- Example:
// Final methods can be optimized // Small overhead per virtual call
How to Use
- Extension: Customize parent behavior
- Annotation: Always use @override
- Super: Call parent when appropriate
- Design: Limit deep hierarchies
How It Works
- VTable: Method lookup table
- Dispatch: Runtime type check
- Optimization: JIT specialization
- Inlining: Possible for final
Example:
abstract class Logger {
void log(String message);
}
class ConsoleLogger extends Logger {
@override
void log(String message) {
print('[Console] $message');
}
}
class FileLogger extends Logger {
@override
void log(String message) {
// Write to file
}
}
void logMessage(Logger logger, String msg) {
logger.log(msg); // Dynamic dispatch
}
Conclusion
Method overriding and dynamic dispatch form the foundation of runtime polymorphism in Dart, enabling flexible and extensible class hierarchies. The explicit @override annotation and clear super call syntax help maintain robust code while the runtime system efficiently handles virtual method calls.