Kotlin inheritance

Inheritance is one of the key features of object-oriented programming. It allows user to create a new class (derived class) from an existing class (base class).

The derived class inherits all the features from the base class and can have additional features of its own.

Before going into details about Kotlin inheritance, we recommend you to check these two articles:

  • Kotlin Class and Objects
  • Kotlin Primary Constructor

Why inheritance?

Suppose, in your application, you want three characters – a math teacher, a footballer and a businessman.

Since, all of the characters are persons, they can walk and talk. However, they also have some special skills. A math teacher can teach math, a footballer can play football and a businessman can run a business.

You can individually create three classes who can walk, talk and perform their special skill.

Example of classes sharing same features without the use of inheritance.

In each of the classes, you would be copying the same code for walk and talk for each character.

If you want to add a new feature – eat, you need to implement the same code for each character. This can easily become error prone (when copying) and duplicate codes.

It would be a lot easier if we had a Person class with basic features like talk, walk, eat, sleep, and add special skills to those features as per our characters. This is done using inheritance.

Example of inheritance in OOP

Using inheritance, now you don’t implement the same code for walk()talk() and eat() for each class. You just need to inherit them.

So, for MathTeacher (derived class), you inherit all features of a Person (base class) and add a new feature teachMath(). Likewise, for the Footballer class, you inherit all the features of the Person class and add a new feature playFootball() and so on.

This makes your code cleaner, understandable and extendable.

It is important to remember: When working with inheritance, each derived class should satisfy the condition whether it “is a” base class or not. In the example above, MathTeacher is a PersonFootballer is a Person. You cannot have something like, Businessman is a Business.


Kotlin inheritance

Let’s try to implement the above discussion in code:

open class Person(age: Int) {
    // code for eating, talking, walking
}

class MathTeacher(age: Int): Person(age) {
    // other features of math teacher
}

class Footballer(age: Int): Person(age) {
    // other features of footballer
}

class Businessman(age: Int): Person(age) {
    // other features of businessman
}

Here, Person is a base class, and classes MathTeacherFootballer, and Businessman are derived from the Person class.

Notice, the keyword open before the base class, Person. It’s important.

By default, classes in Kotlin are final. If you are familiar with Java, you know that a final class cannot be subclassed. By using the open annotation on a class, compiler allows you to derive new classes from it.


Example: Kotlin Inheritance

open class Person(age: Int, name: String) {
    init {
        println("My name is $name.")
        println("My age is $age")
    }
}

class MathTeacher(age: Int, name: String): Person(age, name) {

    fun teachMaths() {
        println("I teach in primary school.")
    }
}

class Footballer(age: Int, name: String): Person(age, name) {
    fun playFootball() {
        println("I play for LA Galaxy.")
    }
}

fun main(args: Array<String>) {
    val t1 = MathTeacher(25, "Jack")
    t1.teachMaths()

    println()

    val f1 = Footballer(29, "Christiano")
    f1.playFootball()
}

When you run the program, the output will be:

My name is Jack.
My age is 25
I teach in primary school.

My name is Cristiano.
My age is 29
I play for LA Galaxy.

Here, two classes MathTeacher and Footballer are derived from the Person class.

The primary constructor of the Person class declared two properties: age and name, and it has an initializer block. The initilizer block (and member functions) of the base class Person can be accessed by the objects of derived classes (MathTeacher and Footballer).

Derived classes MathTeacher and Footballer have their own member functions teachMaths() and playFootball() respectively. These functions are accessible only from the objects of their respective class.


When the object t1 of MathTeacher class is created,

val t1 = MathTeacher(25, "Jack")

The parameters are passed to the primary constructor. In Kotlin, init block is called when the object is created. Since, MathTeacher is derived from Person class, it looks for initializer block in the base class (Person) and executes it. If the MathTeacher had init block, the compiler would have also executed the init block of the derived class.

Next, the teachMaths() function for object t1 is called using t1.teachMaths() statement.

The program works similarly when object f1 of Footballer class is created. It executes the init block of the base class. Then, the playFootball() method of Footballer class is called using statement f1.playFootball().


Important Notes: Kotlin Inheritance

  • If the class has a primary constructor, the base must be initialized using the parameters of the primary constructor. In the above program, both derived classes have two parameters age and name, and both these parameters are initialized in primary constructor in the base class.

    Here’s another example:open class Person(age: Int, name: String) { // some code } class Footballer(age: Int, name: String, club: String): Person(age, name) { init { println("Football player $name of age $age and plays for $club.") } fun playFootball() { println("I am playing football.") } } fun main(args: Array<String>) { val f1 = Footballer(29, "Cristiano", "LA Galaxy") } Here the primary constructor of the derived class has 3 parameters, and the base class has 2 parameters. Note that, both parameters of the base class are initialized.
     
  • In case of no primary constructor, each base class has to initialize the base (using super keyword), or delegate to another constructor which does that. For example,fun main(args: Array<String>) { val p1 = AuthLog("Bad Password") } open class Log { var data: String = "" var numberOfData = 0 constructor(_data: String) { } constructor(_data: String, _numberOfData: Int) { data = _data numberOfData = _numberOfData println("$data: $numberOfData times") } } class AuthLog: Log { constructor(_data: String): this("From AuthLog -> + $_data", 10) { } constructor(_data: String, _numberOfData: Int): super(_data, _numberOfData) { } }To learn more on how this program works, visit Kotlin Secondary Constructor.

Overriding Member Functions and Properties

If the base class and the derived class contains a member function (or property) with the same name, you can need to override the member function of the derived class using override keyword, and use open keyword for the member function of the base class.


Example: Overriding Member Function

// Empty primary constructor
open class Person() {
    open fun displayAge(age: Int) {
        println("My age is $age.")
    }
}

class Girl: Person() {

    override fun displayAge(age: Int) {
        println("My fake age is ${age - 5}.")
    }
}

fun main(args: Array<String>) {
    val girl = Girl()
    girl.displayAge(31)
}

When you run the program, the output will be:

My fake age is 26.

Here, girl.displayAge(31) calls the displayAge() method of the derived class Girl.


You can override property of the base class in similar way.

Visit how Kotlin getters and setters work in Kotlin before you check the example below.

// Empty primary constructor
open class Person() {
    open var age: Int = 0
        get() = field

        set(value) {
            field = value
        }
}

class Girl: Person() {

    override var age: Int = 0
        get() = field

        set(value) {
            field = value - 5
        }
}

fun main(args: Array<String>) {

    val girl = Girl()
    girl.age = 31
    println("My fake age is ${girl.age}.")
}

When you run the program, the output will be:

My fake age is 26.

As you can see, we have used override and open keywords for age property in derived class and base class respectively.


Calling Members of Base Class from Derived Class

You can call functions (and access properties) of the base class from a derived class using super keyword. Here’s how:

open class Person() {
    open fun displayAge(age: Int) {
        println("My actual age is $age.")
    }
}

class Girl: Person() {

    override fun displayAge(age: Int) {

        // calling function of base class
        super.displayAge(age)
        
        println("My fake age is ${age - 5}.")
    }
}

fun main(args: Array<String>) {
    val girl = Girl()
    girl.displayAge(31)
}

When you run the program, the output will be:

My age is 31.
My fake age is 26.

C++ Function Overriding

In this article, you will learn about function overriding. Also, you will learn how can assess the overridden function of the base class in C++ programming.

Inheritance allows software developers to derive a new class from the existing class. The derived class inherits features of the base class (existing class).

Suppose, both base class and derived class have a member function with same name and arguments (number and type of arguments).

If you create an object of the derived class and call the member function which exists in both classes (base and derived), the member function of the derived class is invoked and the function of the base class is ignored.

This feature in C++ is known as function overriding.

How function overriding works in C++?

How to access the overridden function in the base class from the derived class?

To access the overridden function of the base class from the derived class, scope resolution operator :: is used. For example,

If you want to access getData() function of the base class, you can use the following statement in the derived class.

Base::getData();
Access the overriden function in the base class in C++

C++ Function Overloading

In this tutorial, we will learn about the function overloading in C++ with examples.

In C++, two functions can have the same name if the number and/or type of arguments passed is different.

These functions having the same name but different arguments are known as overloaded functions. For example:

// same number different arguments
int test() { }
int test(int a) { }
float test(double a) { }
int test(int a, double b) { }

Here, all 4 functions are overloaded functions.

Notice that the return types of all these 4 functions are not the same. Overloaded functions may or may not have different return types but they must have different arguments. For example,

// Error code
int test(int a) { }
double test(int b){ }

Here, both functions have the same name, the same type, and the same number of arguments. Hence, the compiler will throw an error.


Function Overloading using Different Types of Parameter

// Program to compute absolute value
// Works for both int and float

#include <iostream>
using namespace std;

// function with float type parameter
float absolute(float var){
    if (var < 0.0)
        var = -var;
    return var;
}

// function with int type parameter
int absolute(int var) {
     if (var < 0)
         var = -var;
    return var;
}

int main() {
    
    // call function with int type parameter
    cout << "Absolute value of -5 = " << absolute(-5) << endl;

    // call function with float type parameter
    cout << "Absolute value of 5.5 = " << absolute(5.5f) << endl;
    return 0;
}

Run Code

Output

Absolute value of -5 = 5
Absolute value of 5.5 = 5.5
Working of C++ Function Overloading for absolute()
Working of overloading for the absolute() function

In this program, we overload the absolute() function. Based on the type of parameter passed during the function call, the corresponding function is called.


Function Overloading using Different Number of Parameters

#include <iostream>
using namespace std;

// function with 2 parameters
void display(int var1, double var2) {
    cout << "Integer number: " << var1;
    cout << " and double number: " << var2 << endl;
}

// function with double type single parameter
void display(double var) {
    cout << "Double number: " << var << endl;
}

// function with int type single parameter
void display(int var) {
    cout << "Integer number: " << var << endl;
}

int main() {

    int a = 5;
    double b = 5.5;

    // call function with int type parameter
    display(a);

    // call function with double type parameter
    display(b);

    // call function with 2 parameters
    display(a, b);

    return 0;
}

Run Code

Output

Integer number: 5
Float number: 5.5
Integer number: 5 and double number: 5.5

Here, the display() function is called three times with different arguments. Depending on the number and type of arguments passed, the corresponding display() function is called.

Working of C++ Function Overloading for display()
Working of overloading for the display() function

The return type of all these functions is the same but that need not be the case for function overloading.


Note: In C++, many standard library functions are overloaded. For example, the sqrt() function can take doublefloatint, etc. as parameters. This is possible because the sqrt() function is overloaded in C++.