Skip to content

Inheritance Tutorial

Benedict Allen edited this page Nov 15, 2015 · 5 revisions

Inheritance Tutorial

Overview

Sometimes, multiple classes share a common 'base'. For example, all GUI components have a position which can be animated, an ID, a width and height, and potentially a parent. It would be ridiculous to implement this code over and over in each element, so we use something called 'inheritance'.

Simply put, there is one class (a 'super' class), which contains the generic, shared, properties and methods, and then other classes ('child' or 'sub' classes) which 'extend' the super class.

Syntactically, you define a sub/child class like so:

class "Sub" extends "Super" {

}

All the properties and methods of the super class will be present in the child unless overridden. You could say that the sub-classes inherit the values from the super class.

Any class can extend any other class. However, a class can only extend one other class. Multiple inheritance is not supported. See Interfaces Tutorial if multiple inheritance is required.

Constructors

Along with inheritance comes issues when it comes to constructors. If the child class has no constructor, the super class' constructor will be used. However, if the child class has a constructor, the super class' constructor will not be called automatically. This is good as the developer can control what code is run, but can also lead to problems if the class is not initialised correctly.

To call the constructor of the super class, use

self:SuperClassName( ... )

In 9/10 cases, it will be essential to call the super's constructor. However, arguments can be modified to any extent before the super constructor is called, and code can be executed before and after the super's constructor is called.

Beware, however, that if the developer passes in an incorrect type parameter that isn't type checked by a child constructor, the super constructor may throw an exception pointing to the child constructor rather than the developer's code. To get around this, it is worth using a tail-call at the end of the child constructor:

return self:SuperClassName( ... )

Accessing super values

A child class is perfectly capable of overriding a method. Sometimes, it is necessary to do this, but still use the original. For cases like this, instances have access to self.super. self.super is, in ways, the instance created as if it were a member of its super class. By using self.super:method(), you can call the method of the super class, rather than the overridden method of the instance itself. If the member class extends a class which extends another class, you can use self.super.super, and so on.

-- Create a new empty class called Base
class "Base" {}

-- Create a method for the Base class called Base:print()
function Base:print()
    print( "I was printed" )
end

-- Create a new empty class called Child that will extend Base
class "Child" extends "Base" {}

-- While Child inherits its methods from Base and therefore already contains Child:print() (with the same functionality as Base:print()), we will override this method and replace it with a new one
function Child:print()
    -- Our custom method will print its own text at first
    print( "I was overridden, but..." )
    
    -- But then also call the /original/ function of Child's super class (the Base class)
    self.super:print()
end

-- Create a new instance of Child
local a = Child()

-- Call the overridden method Child:print()
a:print()
-- The output will show us that Child:print() was called and then proceeded to call Child.super:print() (Base:print())
--> I was overridden, but...
--> I was printed

-- Create a new instance of Base
local b = Base()

-- Call the method Base:print()
b:print()
-- The Base:print() method is still the original function
--> I was printed

When and when not to use inheritance

  • Child classes use 90%+ of the super class.
  • More than one child class.
  • Children have a lot in common.
  • Many of the child classes don't use things from the super class.
  • Just one child class.
  • Children have very little in common.

Clone this wiki locally