Bridge Software Pattern C++ Examples

The Bridge pattern in C++ allows you to separate an abstraction from its implementation, enabling them to vary independently. Here are three examples of implementing the Bridge pattern in C++

Table of Contents

Example 1: Basic Bridge Pattern

#include <iostream>

// Implementor interface
class Implementor {
public:
    virtual void operationImp() = 0;
};

// Concrete Implementors
class ConcreteImplementorA : public Implementor {
public:
    void operationImp() override {
        std::cout << "Concrete Implementor A operation" << std::endl;
    }
};

class ConcreteImplementorB : public Implementor {
public:
    void operationImp() override {
        std::cout << "Concrete Implementor B operation" << std::endl;
    }
};

// Abstraction
class Abstraction {
protected:
    Implementor* implementor;

public:
    Abstraction(Implementor* imp) : implementor(imp) {}

    virtual void operation() {
        std::cout << "Abstraction operation" << std::endl;
        implementor->operationImp();
    }
};

// Refined Abstractions
class RefinedAbstraction1 : public Abstraction {
public:
    RefinedAbstraction1(Implementor* imp) : Abstraction(imp) {}

    void operation() override {
        std::cout << "Refined Abstraction 1 operation" << std::endl;
        implementor->operationImp();
    }
};

class RefinedAbstraction2 : public Abstraction {
public:
    RefinedAbstraction2(Implementor* imp) : Abstraction(imp) {}

    void operation() override {
        std::cout << "Refined Abstraction 2 operation" << std::endl;
        implementor->operationImp();
    }
};

int main() {
    Implementor* implementorA = new ConcreteImplementorA();
    Implementor* implementorB = new ConcreteImplementorB();

    Abstraction* abstraction1 = new RefinedAbstraction1(implementorA);
    Abstraction* abstraction2 = new RefinedAbstraction2(implementorB);

    abstraction1->operation();
    abstraction2->operation();

    delete implementorA;
    delete implementorB;
    delete abstraction1;
    delete abstraction2;

    return 0;
}

In this C++ example, we have an Implementor interface, concrete implementors ConcreteImplementorA and ConcreteImplementorB, an Abstraction class, and refined abstractions RefinedAbstraction1 and RefinedAbstraction2. The Bridge pattern allows different abstractions to work with different implementors.

Example 2: Bridge Pattern with Function Pointers

#include <iostream>

// Implementor interface
typedef void (*OperationImp)();

// Concrete Implementors
void concreteImplementorAOperation() {
    std::cout << "Concrete Implementor A operation" << std::endl;
}

void concreteImplementorBOperation() {
    std::cout << "Concrete Implementor B operation" << std::endl;
}

// Abstraction
class Abstraction {
private:
    OperationImp operationImp;

public:
    Abstraction(OperationImp opImp) : operationImp(opImp) {}

    void operation() {
        std::cout << "Abstraction operation" << std::endl;
        operationImp();
    }
};

// Refined Abstractions
void refinedAbstraction1Operation() {
    std::cout << "Refined Abstraction 1 operation" << std::endl;
    concreteImplementorAOperation();
}

void refinedAbstraction2Operation() {
    std::cout << "Refined Abstraction 2 operation" << std::endl;
    concreteImplementorBOperation();
}

int main() {
    Abstraction abstraction1(refinedAbstraction1Operation);
    Abstraction abstraction2(refinedAbstraction2Operation);

    abstraction1.operation();
    abstraction2.operation();

    return 0;
}

This C++ example uses function pointers to implement the Bridge pattern, allowing abstractions to work with different implementors through function calls.

Example 3: Bridge Pattern with Data Structures

#include <iostream>
#include <string>

// Implementor interface
class Implementor {
public:
    virtual void operationImp(void* data) = 0;
};

// Concrete Implementors
class ConcreteImplementorA : public Implementor {
public:
    void operationImp(void* data) override {
        std::string* strData = static_cast<std::string*>(data);
        std::cout << "Concrete Implementor A operation with data: " << *strData << std::endl;
    }
};

class ConcreteImplementorB : public Implementor {
public:
    void operationImp(void* data) override {
        int* intData = static_cast<int*>(data);
        std::cout << "Concrete Implementor B operation with data: " << *intData << std::endl;
    }
};

// Abstraction
class Abstraction {
protected:
    Implementor* implementor;

public:
    Abstraction(Implementor* imp) : implementor(imp) {}

    virtual void operation(void* data) {
        std::cout << "Abstraction operation" << std::endl;
        implementor->operationImp(data);
    }
};

// Refined Abstractions
class RefinedAbstraction1 : public Abstraction {
public:
    RefinedAbstraction1(Implementor* imp) : Abstraction(imp) {}

    void operation(void* data) override {
        std::cout << "Refined Abstraction 1 operation" << std::endl;
        implementor->operationImp(data);
    }
};

class RefinedAbstraction2 : public Abstraction {
public:
    RefinedAbstraction2(Implementor* imp) : Abstraction(imp) {}

    void operation(void* data) override {
        std::cout << "Refined Abstraction 2 operation" << std::endl;
        implementor->operationImp(data);
    }
};

int main() {
    Implementor* implementorA = new ConcreteImplementorA();
    Implementor* implementorB = new ConcreteImplementorB();

    std::string strData = "Data for Implementor A";
    int intData = 42;

    Abstraction* abstraction1 = new RefinedAbstraction1(implementorA);
    Abstraction* abstraction2 = new RefinedAbstraction2(implementorB);

    abstraction1->operation(&strData);
    abstraction2->operation(&intData);

    delete implementorA;
    delete implementorB;
    delete abstraction1;
    delete abstraction2;

    return 0;
}

In this C++ example, we use data structures as the implementors’ input. This allows different implementors to operate on different data types while maintaining a common abstraction.

Dane Stuckel Photo
Written and maintained by Dane Stuckel.
To like, comment or give feedback,
please share on social media.
Follow the author for more content like this.