SOLID Principles in C++: Theory and Practice from A to Z

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

SOLID Principles in C++: Theory and Practice from A to Z



SOLID is an acronym representing five fundamental principles of object-oriented programming and design, formulated by Robert Martin (also known as "Uncle Bob"). For C++, these principles are especially important as they allow you to create flexible, maintainable, and testable code that is easy to scale. In this article, we will break down each principle from a theoretical perspective and support it with practical examples in C++.



What is SOLID and why is it needed?

SOLID is a set of rules that helps a developer avoid "bad" code. Adhering to these principles leads to reduced coupling and increased cohesion of modules. In C++, where powerful template capabilities and multiple inheritance can easily lead to chaos, SOLID serves as a reliable compass. Each letter of the acronym stands for the following:

  • S — Single Responsibility Principle
  • O — Open-Closed Principle
  • L — Liskov Substitution Principle
  • I — Interface Segregation Principle
  • D — Dependency Inversion Principle


Single Responsibility Principle

Theory: A class should have only one reason to change. In other words, a class should be responsible for only one part of the program's functionality.

Practice in C++: Violating this principle often leads to "god objects" that do everything at once.

// ❌ Bad: class violates SRPclass Report {public:    void generateReport() { /* data generation */ }    void saveToFile(const std::string& filename) { /* writing to file */ }    void printReport() { /* sending to printer */ }};

// ✅ Good: separate responsibilitiesclass ReportData {public: std::string generate() { return "Report data"; }};

class ReportSaver {public: void save(const std::string& data, const std::string& filename) { std::ofstream file(filename); file << data; }};

class ReportPrinter {public: void print(const std::string& data) { /* printing */ }};

In the good example, each class is responsible for its own task. This simplifies testing and code modification.



Open-Closed Principle

Theory: Software entities (classes, modules, functions) should be open for extension but closed for modification.

Practice in C++: Achieved through abstraction and polymorphism.

// ❌ Bad: to add a new shape, you need to change the codeclass AreaCalculator {public:    double calculateArea(std::string shapeType, double param) {        if (shapeType == "circle") {            return 3.14 * param * param;        } else if (shapeType == "square") {            return param * param;        }        return 0.0;    }};

// ✅ Good: use polymorphismclass Shape {public: virtual double area() const = 0; virtual ~Shape() = default;};

class Circle : public Shape { double radius;public: Circle(double r) : radius(r) {} double area() const override { return 3.14159 * radius * radius; }};

class Square : public Shape { double side;public: Square(double s) : side(s) {} double area() const override { return side * side; }};

class AreaCalculatorOCP {public: double calculate(const Shape& shape) { return shape.area(); }};

Now, to add a new shape (e.g., a triangle), you don't need to change A

Blogs

Book Recommendations