Event Bus and Observer Pattern in C++: Implementation and Examples

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Event Bus and Observer Pattern in C++: From Theory to Practice



In modern C++ software development, loose coupling of components plays an important role. The Observer pattern and its evolution — the Event Bus — provide an elegant mechanism for organizing interaction between objects without creating rigid dependencies. In this article, we will thoroughly examine how to implement these patterns in C++, discuss their advantages and limitations, and provide practical code examples.



Observer Pattern: Classic Implementation



The Observer pattern defines a one-to-many relationship between objects: when one object (the subject) changes its state, all dependent objects (observers) are automatically notified. In C++, the classic implementation looks like this:



#include <iostream>#include <vector>#include <memory>#include <algorithm>

// Observer interfaceclass IObserver {public: virtual ~IObserver() = default; virtual void update(const std::string& message) = 0;};

// Concrete observerclass ConcreteObserver : public IObserver {private: std::string name;public: explicit ConcreteObserver(const std::string& n) : name(n) {} void update(const std::string& message) override { std::cout << "[" << name << "] Received: " << message << std::endl; }};

// Subject (observable object)class Subject {private: std::vector<std::shared_ptr<IObserver>> observers; std::string state;public: void attach(std::shared_ptr<IObserver> observer) { observers.push_back(observer); } void detach(std::shared_ptr<IObserver> observer) { observers.erase( std::remove(observers.begin(), observers.end(), observer), observers.end() ); } void notify() { for (auto& observer : observers) { observer->update(state); } } void setState(const std::string& newState) { state = newState; notify(); }};

int main() { Subject subject; auto obs1 = std::make_shared<ConcreteObserver>("Observer 1"); auto obs2 = std::make_shared<ConcreteObserver>("Observer 2"); subject.attach(obs1); subject.attach(obs2); subject.setState("Event #1 occurred!"); subject.detach(obs1); subject.setState("Event #2 without the first observer"); return 0;}


Event Bus: Centralized Event Bus



The Event Bus extends the Observer idea by providing a centralized message exchange mechanism. Instead of each subject storing a list of observers, all subscriptions and publications go through a single bus. This allows:

  • Reduced coupling — senders and receivers know nothing about each other.
  • Simplified scaling — new event types are added without changing existing code.
  • Flexibility — subscribers can be added and removed at runtime.


Example implementation of an Event Bus in C++ using templates and std::function:



#include <iostream>#include <unordered_map>#include <functional>#include <any>#include <typeindex>#include <vector>#include <memory>

// Base class for eventsstruct Event { virtual ~Event() = default;};

// Concrete eventstruct UserLoginEvent : public Event { std::string username; explicit UserLoginEvent(std::string name) : username(std::move(name)) {}};

// Event Bus classclass EventBus {private: std::unordered_map<std::type_index, std::vector<std::function<void(const std::any&)>>> hand

Recommendations