beginner_intermediate

Dependência cíclica de headers

Uma coisa que acaba atrapalhando quem está começando no C++ é a dependência cíclica dos headers. Quando estamos escrevendo programas minúsculos isso não acontece, mas é um cenário muito comum.

Antes de falar mais sobre as dependências, vamos entender um pouco da inclusão destes headers. Como funciona o famoso #include ?

Supondo que temos 3 arquivos: main.cpp, main.h e int_vector.h, com o seguinte conteúdo:

Ao compilar o arquivo main.cpp, será feito um pré-processamento de macros (como o #include) e será gerado um arquivo de saída como este abaixo.

Então, o que seria a dependência cíclica ?

Conforme vimos, o pré-processador junta todos os arquivos referenciados em uma diretiva #include em um arquivo só. Quando um header inclui um outro header e este outro inclui o primeiro, o que o pré-processador deve fazer ?

Temos uma solução fácil para isso, mas antes vamos imaginar o seguinte cenário:
Nós temos uma main_window que pode ter uma janela filha e a main_window vai fechar a janela.

Vamos ver uma implementação inicial desse cenário

Simples e direto. A main_window invoca o window::close.

Porém, vamos supor que o fechamento dessa janela pode ser impedido, ou seja, o window::close talvez não seja bem sucedido e este processamento é assíncrono.

Para isso, é necessário alertar o main_window que a janela foi fechada com sucesso.

Neste caso, é preciso que o main_window conheça o window, uma vez que vai ser invocado o close, mas também é preciso que o window conheça o main_window, já que ao ser invocado, ele vai alertar que window::close foi bem sucedido.

Uma forma inicial é:

Isso gera o problema de dependência cíclica, já que temos:

  • main_window.h incluindo o window.h
  • window.h incluindo o main_window.h
  • E assim indo sucessivamente, para todo o sempre.

Solução do problema

Para resolvermos este problema, precisamos definir um tipo incompleto (forward declaration na terminologia do C++)

A linha struct main_window declara que uma classe incompleta main_window existe e será declarada posteriormente. Por ser um tipo incompleto, o compilador não conhece o seu tamanho, então somente temos esse tipo incompleto na forma de ponteiro ou referência.
Ex: main_window &_parent ou *_parent

Na implementação é preciso fazer o include do window.h para que este saiba onde encontrar o layout da classe incompleta usada

Essa forma de declaração é necessária devido ao C++ usar value_type por padrão e pela forma como a struct/classe fica em memória. Para o post não ficar muito extenso, isso será explicado em um próximo artigo. 🙂

Fonte: https://github.com/SimplyCpp/examples/tree/master/dependencia

1 Comment

Leave a Reply

Your email address will not be published. Required fields are marked *