Ir para o conteúdo

Última atualização:2026-10-12

Injeção de dependência em C++

Ultimamente, um colega da comunidade pediu para atualizar o tema injeção de dependência, então escrevi este artigo, explicando a partir de exemplos práticos; o texto cobre alguns princípios e implementações, e a versão completa do código está disponível na comunidade. Vamos ao texto.

Roteiro:

  • dependência direta
  • injeção de dependência por interface
  • injeção de dependência por template

A injeção de dependência é um design pattern muito usado; normalmente adota-se a abordagem por interface/template para melhorar a testabilidade e a manutenibilidade do código. Vejamos um exemplo.

Suponha que haja uma classe de serviço de usuário, UserService, que precisa se comunicar com um servidor remoto por meio de um cliente HTTP; nesse caso, poderíamos escrever as três implementações a seguir.

1. Dependência direta

UserService depende diretamente de HttpClient internamente; por exemplo:

class HttpClient {
 public:
  std::string Get(const std::string& url);
  void Post(const std::string& url, const std::string& data);
};

class UserService {
 private:
  HttpClient m_httpClient;
};

Dentro de UserService geralmente haveria alguns métodos para operar m_httpClient; essa abordagem é simples e direta, mas acopla UserService a um HttpClient concreto, o que torna difícil substituir o objeto de dependência e difícil fazer testes de unidade.

Daí surgem os dois métodos a seguir.

2. Injeção de dependência por interface

Nosso objetivo é que o teste seja conveniente, sem a necessidade de criar uma classe concreta — o usuário pode criar por mock uma classe para testar; então lembramos das interfaces: extraímos HttpClient e obtemos:

struct IHttpClient {
  virtual std::string Get(const std::string& url) = 0;
  virtual void Post(const std::string& url, const std::string& data) = 0;
  virtual ~IHttpClient() = default;
};
class UserService {
 private:
  std::unique_ptr<IHttpClient> m_httpClient;
};

Assim, no momento do teste, pode-se criar por mock um client para testar; por exemplo:

class MockHttpClient : public IHttpClient {
public:
  MOCK_METHOD(std::string, Get, (const std::string& url), (override));
  MOCK_METHOD(void, Post, (const std::string& url, const std::string& data), (override));
};

auto mockHttpClient = std::make_unique<MockHttpClient>();
UserService userService(std::move(mockHttpClient));

Após essa transformação, conseguimos:

  • esconder os detalhes de implementação no arquivo .cc
  • trabalhar com interfaces abstratas
  • injetar as dependências durante a construção do objeto

3. Injeção de dependência por template

A injeção de dependência por template usa a técnica de templates de C++ para passar o objeto de dependência como parâmetro de template a UserService. Ao instanciar o template, especifica-se a implementação concreta do cliente HTTP. Esse método resolve a dependência em tempo de compilação, sem chamadas de funções virtuais, melhorando o desempenho. Ao mesmo tempo, permite que a classe UserService se integre de forma flexível com diferentes implementações de cliente HTTP e facilita os testes de unidade.

template <typename THttpClient>
class UserService {
 private:
  THttpClient m_httpClient;
};

Nesse caso, é bem fácil testar; por exemplo:

UserService<MockHttpClient> userService;

Essa abordagem traz os seguintes benefícios:

  • injetar as dependências durante a instanciação do template
  • sem chamadas virtuais (note que THttpClient não é uma interface, de modo que as chamadas podem ser resolvidas em tempo de compilação)

Este é todo o conteúdo desta seção; o código completo está na comunidade — assine e baixe!

Tópicos relacionados

Comentários