41. Abstract Communication Driver UART vs SPI

#include <iostream>
#include <string>
using namespace std;

class CommDriver {
public:
    virtual void send(const string& data) = 0;
    virtual string receive() = 0;
    virtual ~CommDriver() = default;
};

class UartDriver : public CommDriver {
private:
    string last;
public:
    void send(const string& data) override {
        last = data;
        cout << "UART SEND: " << data << "\n";
    }
    string receive() override {
        return string("UART RECV: ") + last;
    }
};

class SpiDriver : public CommDriver {
private:
    string last;
public:
    void send(const string& data) override {
        last = data;
        cout << "SPI SEND: " << data << "\n";
    }
    string receive() override {
        return string("SPI RECV: ") + last;
    }
};

int main() {
    string type, msg;
    cin >> type >> msg;

    CommDriver* d = nullptr;
    if (type == "UART") {
        d = new UartDriver();
    } else if (type == "SPI") {
        d = new SpiDriver();
    }

    if (d) {
        d->send(msg);
        cout << d->receive();
        delete d;
    }
    return 0;
}

Solution Details

  • Declaring send and receive as pure virtual (= 0) makes CommDriver an abstract class; you cannot create it directly.
     
  • UartDriver and SpiDriver implement the interface. The base pointer (CommDriver*) enables runtime polymorphism: d->send() and d->receive() dispatch to the correct driver at runtime.
     
  • Layman’s view: CommDriver is a contract that says, “any driver must know how to send and receive.” UART and SPI each fulfill that contract in their own way.
     

Significance for Embedded Developers

  • Mirrors real HAL design: a common driver interface (CommDriver) with multiple transport implementations (UART, SPI, I2C).
     
  • Lets higher-level firmware talk to any communication backend through one API, improving modularity, testability, and portability across hardware.

     
Loading...

Input

UART Hello

Expected Output

UART SEND: Hello UART RECV: Hello