3.7. Abstract Classes

There is another modifier for methods, called abstract. This modifier allows you to describe a method that is not actually implemented in the class. Instead, it must be implemented by subclasses before it can be called. This allows you to define operations that can be called on all instances of a type, whilst ensuring that all more specific types provide their own version of the functionality.

A class containing abstract methods must be declared abstract as well. The result of this is to prevent any instantiation of the type.

public abstract class Animal : Object {

    public void eat() {
        stdout.printf("*chomp chomp*\n");
    }

    public abstract void say_hello();
}

public class Tiger : Animal {

    public override void say_hello() {
        stdout.printf("*roar*\n");
    }
}

public class Duck : Animal {

    public override void say_hello() {
        stdout.printf("*quack*\n");
    }
}

The implementation of an abstract method must be marked with override. Properties may be abstract as well.

3.7.1. Virtual Methods

A virtual method allows to define default implementations to abstract classes and allows to derived classes to override its behavior, this is different than hiding methods.

public abstract class Caller : GLib.Object {
   public abstract string name { get; protected set; }
   public abstract void update (string new_name);
   public virtual bool reset ()
   {
      name = "No Name";
      return true;
   }
}

public class ContactCV : Caller
{
   public override string name { get; protected set; }
   public override void update (string new_name)
   {
     name = "ContactCV - " + new_name;
   }
   public override bool reset ()
   {
      name = "ContactCV-Name";
      stdout.printf ("CotactCV.reset () implementation!\n");
      return true;
   }
}

public class Contact : Caller {
   public override string name { get; protected set; }
   public override void update (string new_name)
   {
     name = "Contact - " + new_name;
   }

   public static void main ()
   {
      var c = new Contact ();
      c.update ("John Strauss");
      stdout.printf(@"Name: $(c.name)\n");
      c.reset ();
      stdout.printf(@"Reset Name: $(c.name)\n");

      var cv = new ContactCV ();
      cv.update ("Xochitl Calva");
      stdout.printf(@"Name: $(cv.name)\n");
      cv.reset ();
      stdout.printf(@"Reset Name: $(cv.name)\n");
      stdout.printf("END\n");
   }
}

As you can see in the above example, Caller is an abstract class defining both an abstract property and a method, but adds a virtual method which can be overridden by derived classes. Contact class implements abstract methods and properties of Caller, while using the default implementation for reset() by avoiding to define a new one. ContactCV class implements all abstract definitions on Caller, but overrides reset() so as to define its own implementation.