Skip to content

Inheritance

Just like in C++ and many other languages, Class++ allows you to inherit classes. We group the inheritance concept into two categories: derived class (child), and the base class (parent).

local class = ClassPP.class

local Vehicle = class "Vehicle" { -- Base Class
    Public = {
        Brand = "Tesla",
        Model = "S",
        License_Plate = "BITE 1987",
        Year = 2012,
        honk = function(self)
            print("honk honk!")
        end
    }
}

local Car = class "Car" (Vehicle, nil) { -- Derived Class
    Public = {
        License_Plate = "A1B2C3"
    }
}

local newCar = Car.new()
newCar:honk()
print(newCar.Brand, newCar.Model, newCar.License_Plate, newCar.Year) -- Prints "Tesla S A1B2C3 2012"!

In this example, we have 2 classes: The Vehicle class (base), and the Car class (child).
We created the Car class by providing the class function a list of classes to inherit from (in this case, only the Vehicle class), and the classData table after.

When you create a class using this method, you create a new derived class that inherits all of the members and member functions from the class(es) provided, so you don't need to re-declare them again. The members are overwritable in the derived class, like in the example above, you can modify the License_Plate's default value to anything you wish. The same applies to other members.

Question

"Why should I use Inheritence?" It's very useful for code reusability: reusing members and functions of an existing class when you're creating a new class will save you a lot of time and effort, defining same members over and over again may cause spaghetti code and decrease code readability.


Multilevel-Inheritance

A class can also be derived from one class, which can be derived from another class:

local class = ClassPP.class

local Person = class "Person" { -- Base Class
    Public = {
        Name = "",
        Age = 0,
        Gender = "",
        Height = 0
    }
}

local Child = class "Child" (Person, nil) { -- Derived Class
    Public = {
        Age = 9,
        Energetic = true
    }
}

local Student = class "Student" (Child, nil) { -- Derived Class from a Derived Class
    Public = {
        SchoolId = 0,
        Grade = 0,
        Behaviour = "Good"
    }
}

local newStudent = Student.new()
print(newStudent.Name, newStudent.Age, newStudent.Gender, newStudent.Height, newStudent.Age, newStudent.Energetic, newStudent.SchoolId, newStudent.Grade, newStudent.Behaviour)
-- Prints " 9  0 9 true 0 0 Good"! (Spaces represent empty strings)

Multi-Inheritance

A class can also be derived from multiple classes:

local class = ClassPP.class

local A = class "A" { 
    Public = {
        Variable_A = 1
    }
}

local B = class "B" { 
    Public = {
        Variable_B = 1
    }
}

local C = class "C" (A, B) { -- Derived Class
    Public = {
        Variable_C = 1
    }
}

local newObject = C.new() -- {Variable_A: number, Variable_B: number, Variable_C: number}

Protected Access Specifier

In the Access Specifiers section, you have learned that there are 4 access specifiers in Class++, so far you have seen Public, Private and Friend. The fourth specifier, Protected, is pretty much the same as the Private, however, aside from the class members, inherited classes will also be able to access these members.

local class = ClassPP.class

local Car = class "Car" {
    Public = {
        Brand = "Lamborghini",
    },
    Protected = {
        License_Plate = "XXXX"
    }
}

local BiggerCar = class "BiggerCar" (Car, nil) {
    Public = {
        Brand = "Tesla"
    }
}

function BiggerCar.Public:printLicensePlate()
    print(self.License_Plate) -- Will print "XXXX"!
end

local newCar = BiggerCar.new()
newCar:printLicensePlate()

In this example, we put the member License_Plate under the Protected access specifier, and created a new class inherited from the Car class. The inherited class and it's member functions will now be able to access this member.


super

Let's say that you want to access a function in the base class from a child class, how would you do it? Creating a new object from the base class and calling the function would be tedious, as it would take longer to write and would decrease performance.

Luckily, in Class++ 2.0, you can call the super method of the object, which allows you to call the function in the base class that has the same name of the function this method has been called from.

local class = ClassPP.class

local A = class "A" { 
    Public = {
        getVariable = function(self)
            return self.Variable_A
        end
    },
    Protected = {
        Variable_A = 1
    }
}

local B = class "B" (A, nil) { 
    Public = {
        Variable_B = 1,
        getVariable = function(self)
            return self:super()
        end
    }
}

local newObject = B.new()
print(newObject:getVariable()) -- 1

In this example, we created a new class called "B" that inherits from "A". In both classes, we have a function called "getVariable", in the base class, this function returns the "Variable_A" member's value, and in the child class, this function returns the value from the "getVariable" function from the parent class, by calling the super() method.

Warning

super cannot be used within classes that have multi-inheritance. This is due to ambiguity that occurs with functions that have the same name in classes that have multi-inheritance.