November 11, 2019
Polymorphism is a technique in object oriented programming that allows for the redefinition of methods for derived classes. A commonly used example of this is having a base class defining a getArea() function that other classes such as circles and squares can inherit from and redefine based on their specific formulas. While OOP languages aren’t often used in embedded systems, these techniques can still be useful for embedded developers looking to take advantage of them.
The Base Class
Here’s an example of using polymorphism in C++ to control a digital output. First we need the base class defining the interface:
// Digital Output interface class
class DigitalOutputInterface {
public:
virtual void on() = 0;
virtual void off() = 0;
virtual void toggle() = 0;
};
The is what will define the functions that our child classes will inherit and implement. C++ has no specific keyword to label an interface class like other languages such as Java, so we must label each function inside as pure virtual with the virtual keyword before the definition and also set the function equal to zero.
The First Child Class
Our first child class will define a digital output that exists on the controller. It inherits from the DigitalOutputInterface base class and implements the virtual functions inside:
class ControllerDigitalOutput : public DigitalOutputInterface {
private:
int pinNumber;
public:
ControllerDigitalOutput(int pinNumber) {
this->pinNumber = pinNumber;
}
void on(void) {
bsp_pinWrite(PIN_HIGH, pinNumber);
}
void off(void) {
bsp_pinWrite(PIN_LOW, pinNumber);
}
void toggle(void) {
bsp_pinWrite(PIN_TOGGLE, pinNumber);
}
};
The functions are essentially wrappers for the bsp call, but it does contain the specific pin information we need to reference it so using it once we have a defined object is easy.
The Second Child Class
Our second child class will also inherit from the DigitalOutputInterface base class but this will define an output on some kind of serial bus.
class BusDigitalOutput : public DigitalOutputInterface {
private:
int busId;
public:
BusDigitalOutput(int busId) {
this->busId = busId;
}
void on(void) {
bsp_busWrite(PIN_HIGH, busId);
}
void off(void) {
bsp_busWrite(PIN_LOW, busId);
}
void toggle(void) {
bsp_busWrite(PIN_TOGGLE, busId);
}
};
This class can be configured to send specific bus information along with the pin state for usage in something like an I2C bus where individual chips have unique addresses. In this case we just save the busId in our constructor for use in addressing the bus later.
Usage
Finally, we have the usage of these classes. Since we have an interface base class, the child classes are guaranteed to have the methods we defined in it, as not overriding them will result in a compilation error.
int main()
{
// Instantiate individual outputs
ControllerDigitalOutput controllerPin(5);
BusDigitalOutput busPin(0b1000);
controllerPin.on();
busPin.on();
controllerPin.off();
busPin.off();
}
This example would be labeled as compile time polymorphism. Runtime polymorphism is more complex and powerful, but often relys on the usage of the ‘new’ keyword which is how C++dynamically allocates memory.
The full program can be found on my Github in the following link:
https://github.com/danbar0/EmbeddedPolymorphism