Home > Blockchain >  Calling child's overridden method from parent class
Calling child's overridden method from parent class

Time:04-24

I want to practice C by coding a simple mobile phone application with an interchangeable system. I created a System base class and also created MyOS class which extends the System class. In the Phone class, I have a variable of System class because I think like in Java, you can assign it with child class. (eg. System sys = new MyOS();). But in C it calls the function in the base class.

What I want to work in C but it's in Java.

public class MyParent {
    public void start() {
        System.out.println("start() executed in MyParent");
    }
}

public class MyChild extends MyParent {
    @Override
    public void start() {
        System.out.println("start() excecuted in MyChild");
    }
}

public class Inherit {
    MyParent parent;
    
    public Inherit(MyParent parent) {
        this.parent = parent;
    }
    
    public void start() {
        parent.start();
    }
}

public class TestInherit {
    public static void main(String[] args) {
        Inherit i = new Inherit(new MyChild());
        i.start();
    }
}

Output: start() excecuted in MyChild

My current c code:

System.h

#pragma once

#include <iostream>

class System {
public:

    void start() {
        std::cout << "Booting System..." << std::endl;
    }
};

MyOS.h

#pragma once

#include <iostream>
#include "System.h"

class MyOS: public System {
public:

    // Override
    void start() {
        std::cout << "Booting MyOS..." << std::endl;
    }
};

Phone.h

#pragma once

#include "System.h"

class Phone {
public:

    Phone(System system) {
        Phone::system = system;
    }

    void start() {
        system.start();
    }

private:

    System system;
};

MyPhone.cpp

#include "MyOS.h"
#include "Phone.h"
#include "System.h"

int main() {
    MyOS os;
    Phone myPhone(os);
    myPhone.start();

    return 0;
}

Output: Booting System...

CodePudding user response:

There are 2 problems with your given code:

Problem 1

The method start is a non-virtual member function so you're not actually overriding it in the MyOS.

So first step is to make it virtual as shown below.

Problem 2

Moreover, in order for runtime binding to work, you must make the call to the virtual-member function using a pointer or a reference to the Base class(which is System) object as shown below:


Solution

Here we make sure that start is a virtual member function and also that the data member system is an lvalue reference to System so that dynamic binding can actually happen.

MyOS.h

#pragma once

#include <iostream>
#include "System.h"

class MyOS: public System {
public:

    // Override
    public: void start() override {    //override keyword added here to make the intention clear
        std::cout << "Booting MyOS..." << std::endl;
    }
};

System.h

#pragma once

#include <iostream>

class System {
public:

    public:
//--vvvvvvv------------------->virtual keyword added here
    virtual void start() {
        std::cout << "Booting System..." << std::endl;
    }
};

Phone.h

#pragma once

#include "System.h"

class Phone {
public:

    Phone(System& psystem):system(psystem){
    }

    void start() {
        system.start();
    }

private:
//--------v----------->lvalue reference to System
    System& system;
};

main.cpp

#include "MyOS.h"
#include "Phone.h"
#include "System.h"

int main() {
    MyOS os;
    Phone myPhone(os);
    myPhone.start();

    return 0;
}

The output of the above program is:

Booting MyOS...

Demo

Note

Note that we can also make the data member system to be a pointer to a System object instead of making it an lvalue reference to a System object. Demo with pointer. Also note in some circumstances, classes used as the root of an inheritance hierarchy should define a virtual destructor. Refer why virtual destructs are used.

CodePudding user response:

If you're coming from java, you need to remember that every class reference in java is implicitly a pointer, so to make equivalent C code, you need to make all interclass references into pointers.

In addition, every method in java is implicitly virtual, so if you want to override them, you need an explicit virtual in C .

So you end up with something like:

#include <iostream>

class System {
public:

    virtual void start() {
        std::cout << "Booting System..." << std::endl;
    }
};

class MyOS: public System {
public:

    // Override
    void start() override {
        std::cout << "Booting MyOS..." << std::endl;
    }
};

class Phone {
public:

    Phone(System *system) {
        this->system = system;
    }

    void start() {
        system->start();
    }

private:

    System *system;
};

int main() {
    MyOS os;
    Phone myPhone(&os);
    myPhone.start();

    return 0;
}

Of course, using raw pointers is a recipe for memory leaks and corruption, as C does not have built in garbage collection. So you generally want to use "smart" pointers instead -- either std::unique_ptr or std::shared_ptr

  •  Tags:  
  • c
  • Related