Introdução: por que o debate POO versus abordagem funcional não acaba?
\n\nSe você já se perguntou qual estilo de programação em C++ escolher para um novo projeto, não está sozinho. O debate entre programação funcional e abordagem orientada a objetos em C++ já dura décadas. De um lado, a POO clássica, ensinada nas universidades. Do outro, as técnicas funcionais modernas trazidas pelos padrões C++11, C++14, C++17 e C++20.
\n\nNo site pythonlib.ru, frequentemente discutimos decisões arquiteturais, e hoje é hora de resolver essa questão de uma vez por todas. Qual estilo é mais rápido? Qual é mais fácil de manter? E o principal: é possível combiná-los?
\n\nNeste artigo, não vamos defender fanaticamente um paradigma. Em vez disso, analisaremos exemplos reais de código, mostraremos os prós e contras de cada abordagem e daremos recomendações práticas. Vamos lá!
\n\nBreve visão geral dos paradigmas em C++
\n\nAntes de nos aprofundarmos, vamos refrescar a memória sobre o que estamos falando.
\n\nProgramação Orientada a Objetos (POO)
\n\nA POO em C++ é baseada em três pilares: encapsulamento, herança e polimorfismo. Você cria classes que combinam dados e métodos para processá-los. Essa é a abordagem clássica que dominou os anos 90 e 2000.
\n\nclass Animal {\npublic:\n virtual void speak() const = 0;\n virtual ~Animal() = default;\n};\n\nclass Dog : public Animal {\npublic:\n void speak() const override {\n std::cout << "Woof!" << std::endl;\n }\n};\n\nclass Cat : public Animal {\npublic:\n void speak() const override {\n std::cout << "Meow!" << std::endl;\n }\n};\n\nvoid makeSound(const Animal& animal) {\n animal.speak();\n}\n\n\nProgramação Funcional (PF)
\n\nA abordagem funcional em C++ não é um Haskell puro, mas sim o uso de ideias da PF dentro de uma linguagem imperativa. Elementos-chave: funções lambda, imutabilidade de dados, funções de ordem superior e composição.
\n\nstd::vector<int> numbers = {1, 2, 3, 4, 5};\n\n// Estilo funcional: filtragem e transformação\nauto result = numbers\n | std::views::filter([](int n) { return n % 2 == 0; })\n | std::views::transform([](int n) { return n * n; });\n\nfor (int n : result) {\n std::cout << n << " "; // Saída: 4 16\n}\n\n\nComparação na prática: três tarefas típicas
\n\nVamos pegar três tarefas reais que um desenvolvedor C++ enfrenta e ver como POO e PF as resolvem.
\n\nTarefa 1: Processamento de uma coleção de dados
\n\nCondição: Temos uma lista de pedidos. Precisamos filtrar os caros (preço > 1000), ordenar por data e exibir os top-5.
\n\nEstilo POO:
\n\nclass OrderProcessor {\npublic:\n void addOrder(Order order) { orders_.push_back(std::move(order)); }\n \n std::vector<Order> getTopExpensiveRecent(int count) const {\n auto filtered = orders_;\n filtered.erase(\n std::remove_if(filtered.begin(), filtered.end(),\n [](const Order& o) { return o.price <= 1000; }),\n filtered.end());\n \n std::sort(filtered.begin(), filtered.end(),\n [](const Order& a, const Order& b) {\n return a.date > b.date;\n });\n \n if (filtered.size() > count) {\n filtered.resize(count);\n }\n return filtered;\n }\n \nprivate:\n std::vector<Order> orders_;\n};\n\n\nEstilo funcional:
\n\nauto getTopExpensiveRecent(const std::vector<Order>& orders, int count) {\n return orders\n | std::views::filter([](const Order& o) { return o.price >