Classes and Object-Oriented Programming

12.1 Classes (Reference Types)

Single inheritance of classes, plus multiple interfaces. All classes inherit from Object.

Methods are virtual by default. final prevents overriding. Private/final methods are non-virtual.

Classes are reference types, so null is possible. Compare identity with is.

class Animal
{
    protected string name;           // visible to subclasses and the module
    private int id;                  // module-private

    this(string name) { this.name = name; }

    void speak() { writeln(name, " makes a sound"); }   // virtual by default
    final string getName() { return name; }             // can't be overridden

    override string toString() const { return "Animal(" ~ name ~ ")"; }
}

class Dog : Animal
{
    this(string name) { super(name); }
    override void speak() { writeln(name, " says Woof"); }   // `override` is required
}

void main()
{
    Animal a = new Dog("Rex");       // heap-allocated (GC) reference
    a.speak();                       // dynamic dispatch → Dog.speak
    if (auto d = cast(Dog) a) writeln("It's a dog");   // downcast (null if it fails)
    writeln(typeid(a));              // runtime type info
}

12.2 Object Methods

String representation (used by writeln) Equality for == Ordering for < etc.

Hashing for associative array keys

12.3 Constructors, Destructors and Static Constructors

Class destructors are finalizers (non-deterministic under the GC). Use structs with destructors, scope objects, or destroy(obj) for deterministic cleanup.

class Service
{
    static Service instance;
    static this() { instance = new Service(); }          // module/thread-local static constructor
    shared static this() { /* runs once per program */ }
    this() { writeln("ctor"); }
    this(int x) { this(); }                               // constructor delegation
    ~this() { /* finalizer: runs on GC collection, order not guaranteed */ }
}

12.4 Scope Classes and Stack Allocation

scope auto obj = new Service();        // allocated on the stack (DIP1000), destroyed at scope exit
import std.typecons : scoped;
auto s = scoped!Service();             // explicit stack allocation

12.5 Nested and Inner Classes

class Outer
{
    int x = 5;
    class Inner { int get() { return x; } }    // has an implicit `outer` reference
    static class StaticNested {}               // no outer reference
}
auto o = new Outer;
auto i = o.new Inner;

12.6 Templates on Classes, super, this and Covariance

class Base { Base clone() { return new Base; } }
class Derived : Base { override Derived clone() { return new Derived; } }   // covariant return