12. Dart Class and Object

12. Dart Class and Object

AI Reading

Quick summary of this article

Dart classes act as blueprints for creating objects, bundling data (fields) and behavior (methods) together. You can define classes with constructors, use getters and setters to control field access, and build hierarchies through inheritance, where subclasses can override inherited methods.

  • Classes are defined with the class keyword, and objects are created by calling the class constructor (the new keyword is optional in Dart 2+).
  • Constructors initialize objects; Dart supports default constructors and named constructors (e.g., Point.origin()) for alternative creation patterns.
  • Getters and setters provide controlled access to private fields (denoted with an underscore like _width), allowing validation before updating values.
  • Dart supports single inheritance using the extends keyword, letting subclasses inherit fields and methods from a superclass and override them with @override.
  • Inheritance can be multi-level, as shown with ElectricCar and AICar extending Car, which itself extends Vehicle, allowing each level to add specific features.

In Dart, classes are blueprints for creating objects, which are instances of those classes. Classes encapsulate data for the object and methods to manipulate that data. Here’s an overview of how classes and objects work in Dart:

Defining a Class

You define a class using the `class` keyword, followed by the class name and the class body enclosed in curly braces `{}`. Here’s a basic example

// Define a class named Person
class Person {
  // Fields (instance variables)
  String name;
  int age;

  // Constructor
  Person(this.name, this.age);

  // Method
  void greet() {
    print('Hello, my name is $name and I am $age years old.');
  }
}

Creating Objects (Instances of a Class)

Once you have defined a class, you can create objects (instances) of that class using the `new` keyword or by directly invoking the constructor (Dart 2 and above allows omitting `new`):

void main() {
  // Create an object of the Person class
  var person1 = Person('Alice', 30);

  // Access fields and call methods using dot notation
  print('Name: ${person1.name}, Age: ${person1.age}');
  person1.greet(); // Output: Hello, my name is Alice and I am 30 years old.

  // Create another object of the Person class
  var person2 = Person('Bob', 25);
  person2.greet(); // Output: Hello, my name is Bob and I am 25 years old.
}
Constructors

Dart classes can have multiple constructors, including named constructors and default constructors. The default constructor initializes the object when it is created. Here’s an example of using named constructors:

class Point {
  int x, y;

  // Default constructor
  Point(this.x, this.y);

  // Named constructor
  Point.origin() {
    x = 0;
    y = 0;
  }
}

void main() {
  var p1 = Point(10, 20); // Using default constructor
  var p2 = Point.origin(); // Using named constructor

  print('Point p1: (${p1.x}, ${p1.y})'); // Output: Point p1: (10, 20)
  print('Point p2: (${p2.x}, ${p2.y})'); // Output: Point p2: (0, 0)
}

Getters and Setters

Dart provides implicit getters and setters for fields, allowing you to control access to fields and perform validation if needed:

class Rectangle {
  double _width, _height;

  Rectangle(this._width, this._height);

  // Getter for width
  double get width => _width;

  // Setter for width
  set width(double value) {
    if (value > 0) {
      _width = value;
    }
  }

  // Method to calculate area
  double area() {
    return _width * _height;
  }
}

void main() {
  var rect = Rectangle(5.0, 10.0);
  print('Initial width: ${rect.width}'); // Output: Initial width: 5.0

  rect.width = 7.0; // Using the setter
  print('Modified width: ${rect.width}'); // Output: Modified width: 7.0

  print('Area of rectangle: ${rect.area()}'); // Output: Area of rectangle: 70.0
}

Inheritance

Dart supports single inheritance, where a class can inherit from another class. Subclasses inherit fields and methods from their superclass and can override them if necessary:

// Base class
class Animal {
  void makeSound() {
    print('Some sound');
  }
}

// Subclass (derived class)
class Dog extends Animal {
  @override
  void makeSound() {
    print('Bark');
  }

  void wagTail() {
    print('Tail wagging');
  }
}

void main() {
  var dog = Dog();
  dog.makeSound(); // Output: Bark
  dog.wagTail();   // Output: Tail wagging
}

Another Example:

// Base class
class Vehicle {
  int wheels;
  int gears;

  Vehicle(this.wheels, this.gears);

  void displaySpecs() {
    print('Vehicle has $wheels wheels and $gears gears.');
  }
}

// Second level class
class Car extends Vehicle {
  bool hasAC;

  Car(int wheels, int gears, this.hasAC) : super(wheels, gears);

  @override
  void displaySpecs() {
    super.displaySpecs();
    print('Car has AC: $hasAC');
  }
}

// Third level class: ElectricCar
class ElectricCar extends Car {
  int batteryCapacity;

  ElectricCar(int wheels, int gears, bool hasAC, this.batteryCapacity)
      : super(wheels, gears, hasAC);

  @override
  void displaySpecs() {
    super.displaySpecs();
    print('Electric Car has battery capacity of $batteryCapacity kWh.');
  }
}

// Third level class: AICar
class AICar extends Car {
  bool hasAI;

  AICar(int wheels, int gears, bool hasAC, this.hasAI)
      : super(wheels, gears, hasAC);

  @override
  void displaySpecs() {
    super.displaySpecs();
    print('AI Car has AI features: $hasAI');
  }
}

void main() {
  var basicCar = Car(4, 5, true);
  var electricCar = ElectricCar(4, 5, true, 75);
  var aiCar = AICar(4, 5, true, true);

  print('Basic Car Specs:');
  basicCar.displaySpecs();
  print('\nElectric Car Specs:');
  electricCar.displaySpecs();
  print('\nAI Car Specs:');
  aiCar.displaySpecs();
}

 

Leave a Reply

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