Princípios SOLID em C++: teoria e prática de nível avançado

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: SOLID no contexto de C++

SOLID é um acrônimo de cinco princípios fundamentais de design orientado a objetos, formulados por Robert Martin. Para C++, como uma linguagem com tipagem estática poderosa, herança múltipla e RAII, esses princípios adquirem um significado especial. Em nível avançado, a compreensão do SOLID permite criar sistemas flexíveis, testáveis e extensíveis, evitando antipadrões como "classe divina" ou acoplamento rígido.

Neste artigo, analisaremos cada princípio com exemplos práticos de código C++ (17/20), focando nas nuances de implementação: uso de std::unique_ptr, std::function, CRTP, destrutores virtuais e expressões idiomáticas modernas.



1. Single Responsibility Principle (SRP) — Princípio da Responsabilidade Única

Formulação: Uma classe deve ter apenas um motivo para ser alterada.

Na prática, isso significa que a classe é responsável por uma entidade de negócio ou uma única operação. A violação do SRP leva ao "acoplamento" de responsabilidades, dificultando os testes e a modificação.

Exemplo de violação

class Report {public:    void generate() { /* criação de dados */ }    void saveToFile(const std::string& path) { /* gravação em arquivo */ }    void sendEmail(const std::string& to) { /* envio */ }};

Aqui, Report é responsável pela geração, salvamento e envio — três motivos para alteração.

Refatoração com SRP

class Report {public:    void generate() { /* criação de dados */ }};

class ReportSaver {public: void save(const Report& report, const std::string& path);};

class EmailSender {public: void send(const Report& report, const std::string& to);};

Agora cada classe tem uma única responsabilidade. Isso simplifica os testes unitários e o reuso.



2. Open/Closed Principle (OCP) — Princípio Aberto/Fechado

Formulação: Entidades de software devem estar abertas para extensão, mas fechadas para modificação.

Em C++, isso é frequentemente implementado através de polimorfismo (funções virtuais) ou templates (CRTP). Para nível avançado, consideraremos ambas as técnicas.

Abordagem polimórfica (funções virtuais)

class Shape {public:    virtual double area() const = 0;    virtual ~Shape() = default;};

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

class Rectangle : public Shape { double w, h;public: Rectangle(double w, double h) : w(w), h(h) {} double area() const override { return w * h; }};

Adicionar uma nova forma (por exemplo, Triangle) não requer alteração das classes existentes — apenas a criação de um novo herdeiro.

Abordagem com template (CRTP — Curiously Recurring Template Pattern)

template<typename Derived>class ShapeBase {public:    double area() const { return static_cast<const Derived*>(this)->area_impl(); }};

class Circle : public ShapeBase<Circle> { double r;public: Circle(double r) : r(r) {} double area_impl() const { return 3.14 * r * r; }};

CRTP fornece polimorfismo estático sem a sobrecarga de chamadas virtuais, o que é crítico para C++ de alto desempenho.



3. Liskov Substitution Principle (LSP) — Princípio da Substituição de Barbara Liskov

Formulação: Objetos de uma classe base devem ser substituíveis por objetos de classes derivadas sem quebrar a correção do programa.

A violação clássica do LSP em C++ é a sobrescrita de um método virtual com enfraquecimento de pré-condições ou fortalecimento de pós-condições. Vamos considerar um exemplo com a hierarquia "Retângulo — Quadrado".

Antipadrão

class Rectangle {protected:\                

Blogs

Book Recommendations