Introducción: ¿por qué no cesa el debate entre POO y enfoque funcional?
\n\nSi alguna vez te has preguntado qué estilo de programación en C++ elegir para un nuevo proyecto, no estás solo. El debate entre la programación funcional y el enfoque orientado a objetos en C++ lleva ya décadas. Por un lado, la POO clásica que se enseñaba en las universidades. Por el otro, las técnicas funcionales modernas que trajeron los estándares C++11, C++14, C++17 y C++20.
\n\nEn el sitio pythonlib.ru solemos discutir decisiones arquitectónicas, y hoy ha llegado el momento de aclarar esta cuestión de una vez por todas. ¿Qué estilo es más rápido? ¿Cuál es más fácil de mantener? Y lo más importante: ¿se pueden combinar?
\n\nEn este artículo no defenderemos fanáticamente un solo paradigma. En su lugar, analizaremos ejemplos reales de código, mostraremos los pros y contras de cada enfoque y daremos recomendaciones prácticas. ¡Allá vamos!
\n\nBreve resumen de los paradigmas en C++
\n\nAntes de profundizar, refresquemos rápidamente de qué estamos hablando.
\n\nProgramación Orientada a Objetos (POO)
\n\nLa POO en C++ se basa en tres pilares: encapsulación, herencia y polimorfismo. Creas clases que combinan datos y métodos para procesarlos. Es el enfoque clásico que dominó en los años 90 y 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\nProgramación Funcional (PF)
\n\nEl enfoque funcional en C++ no es Haskell puro, sino más bien el uso de ideas de la PF dentro de un lenguaje imperativo. Los elementos clave son: funciones lambda, inmutabilidad de datos, funciones de orden superior y composición.
\n\nstd::vector<int> numbers = {1, 2, 3, 4, 5};\n\n// Estilo funcional: filtrado y transformación\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 << " "; // Salida: 4 16\n}\n\n\nComparación práctica: tres tareas típicas
\n\nTomemos tres tareas reales que enfrenta un desarrollador de C++ y veamos cómo las resuelven la POO y la PF.
\n\nTarea 1: Procesamiento de una colección de datos
\n\nCondición: Hay una lista de pedidos, hay que filtrar los caros (precio > 1000), ordenar por fecha y mostrar los 5 primeros.
\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 >