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...
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