Inyección de Dependencias (Dependency Injection) en C++: contenedores y práctica

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Contenedor de Dependency Injection para C++: descripción general y ejemplos prácticos



En el desarrollo moderno con C++, los principios de Inversion of Control (IoC) y Dependency Injection (DI) se aplican cada vez más. Estos patrones permiten crear código débilmente acoplado, comprobable y fácilmente extensible. A diferencia de los lenguajes con memoria administrada (Java, C#), C++ no tiene reflexión incorporada, por lo que la implementación de contenedores DI aquí requiere metaprogramación de plantillas y el uso de estándares modernos (C++11/14/17/20).



En este artículo, veremos tres enfoques populares para la inyección de dependencias en C++: las bibliotecas Boost.DI, Google Fruit y Kangaru, y también escribiremos nuestro propio contenedor simple para comprender la mecánica.



¿Qué es la Inyección de Dependencias?



La Inyección de Dependencias es una técnica mediante la cual un objeto recibe sus dependencias desde el exterior, en lugar de crearlas él mismo. Los principales tipos de DI son:

  • Constructor Injection — las dependencias se pasan a través del constructor.
  • Setter Injection — las dependencias se establecen a través de setters.
  • Interface Injection — las dependencias se pasan a través de una interfaz.


Ejemplo sin DI (acoplamiento fuerte):

class Logger {public:    void log(const std::string& msg) { /* escribir en archivo */ }};

class Service { Logger logger; // Dependencia fuertepublic: void doWork() { logger.log("Work done"); }};


Ejemplo con DI (acoplamiento débil):

class ILogger {public:    virtual ~ILogger() = default;    virtual void log(const std::string& msg) = 0;};

class ConsoleLogger : public ILogger {public: void log(const std::string& msg) override { std::cout << msg << std::endl; }};

class Service { std::shared_ptr<ILogger> logger;public: explicit Service(std::shared_ptr<ILogger> l) : logger(std::move(l)) {} void doWork() { logger->log("Work done"); }};


Descripción general de los contenedores DI para C++



1. Boost.DI

Boost.DI es una de las bibliotecas más populares. Utiliza plantillas de C++14/17 para la resolución automática de dependencias. Admite polimorfismo, ámbitos (singleton, unique) y configuración modular.



Ejemplo de uso:

#include <boost/di.hpp>#include <iostream>

namespace di = boost::di;

class IWriter {public: virtual ~IWriter() = default; virtual void write(const std::string&) = 0;};

class ConsoleWriter : public IWriter {public: void write(const std::string& msg) override { std::cout << msg << std::endl; }};

class App { std::shared_ptr<IWriter> writer;public: explicit App(std::shared_ptr<IWriter> w) : writer(std::move(w)) {} void run() { writer->write("Hello from Boost.DI!"); }};

int main() { auto injector = di::make_injector( di::bind<IWriter>.to<ConsoleWriter>() ); auto app = injector.create<std::unique_ptr<App>>(); app->run(); return 0;}


Ventajas: tipado fuerte, sobrecarga mínima en tiempo de ejecución, soporte para C++14/17.

Desventajas: mensajes de error de compilación complejos, aumento del tiempo de compilación.



2. Google Fruit

Google Fruit es un contenedor de Google que funciona con C++11. Utiliza macros para registrar componentes y admite inyección a través del constructor.



Ejemplo:

#include <fruit/fruit.h>#include <iostream>

class IWriter {public: virtual void write(const std::string&) = 0;};

class ConsoleWriter : public IWriter {publi

Recommendations