Inheritance


The generic language supports multiple inheritance. The syntax of class declarations is upgraded to the following.

class class_name : base1 base2 ... baseN
{
 ...
}

where base1 ... baseN are the base classes. All methods and fields of the base classes are accessible through a reference to the derived class.

A First Example of Inheritance

As a first example, consider the following program.

using system

space inherit1
{
    class point
    {
        x
        y

        point(xset yset) { x = xset y = yset }
    }

    class derived : string point
    {
        derived() : string("hello world") point(100,200) {} 
    }

    inherit1()
    {
       d = derived()
       cout << (string)d << " " << d.x << " " << d.y << "\n"
    }
}

The output of the program is shown below.

hello world 100 200

Note how the fields x and y of the base class are accessed through the derived class reference d. The base classes themselves may be accessed by name through the dot operator as for the string base class. Note that the string base class must be fully qualified by its name space component as well. The point base class may be accessed as d.inherit1::point. The base classes should be initialised through the derived class constructor using the syntax shown above. If you fail to do this, the base class remains uninitialized.

Virtual Functions

Methods, operators and properties may be declared as virtual and overridden in a derived class. Consider the following example.

// the conversion operator string() is virtual. this is not usually the case.

using system

space sampleU
{
    class point
    {
        x
        y

        point(a b)
        {
          x = a
          y = b
        }

        set(a b)
        {
            x = a
            y = b
            cout << (string)this << "\n"
           ~this
         }

         virtual operator string()
         {
              return "(" + (string)x + "," + (string)y + ")"
         }


         virtual operator~()
         {
              cout << (string)this << "\n"
         }
     }

     class derived : integer point
     {
          derived() : integer(1000) point(10,20) {}

          virtual operator string() { return "derived: " + (string)(integer)this + " (" + (string)x + "," + (string)y + ")" }

          virtual operator~()
          {
             cout << "derived operator~: " << (string)this << "\n"
          }
      }

      sampleU()
      {
          D = derived()
          cout << D.x << "\n"
          cout << D.y << "\n"
          D.set(100,200)
          cout << (point)D << "\n"
      }
}

The output of this program is shown below.

10
20
derived: 1000 (100,200)
derived operator~: derived: 1000 (100,200)
derived: 1000 (100,200)

The base class method for point - set, calls the virtual operator string and the virtual operator ~. These are both overridden in the derived class derived. In the output, the derived class version operator string and operator~ are shown.

We have covered overriding methods and operators, but properties can also be virtual. Consider the next program.

// vprop.txt - virtual properties

space vprop
{
    class base
    {
        base() {}

        test_property()
        {
           cout << property << "\n"
        }

        virtual property
        {
            get
            {
                return "base version of property"
            }
         }
     }

     class derived : base
     {
          derived() : base() {}

          virtual property
          {
              get
              {
                  return "derived version of property"
              }
          }
     }

     vprop()
     {
          c = new derived()
          c.test_property()
     }
}

The output of the program is shown below.

derived version of property

The base class method test_property() calls the property called "property". The derived version of this property is invoked because the property is virtual. You can see from the output that this is the case.