o problema da inclusão circular acontece quando precisamos incluir um arquivo cabeçalho dentro de outro. Como em:
//Classe B usa a classe A
#ifndef _B_
#define _B_
#include "classeA.h"
class B{
private:
A a;
public:
};
#endif
//Classe A usa a classe B
#ifndef _A_
#define _A_
#incude "classeB.h"
class A{
private:
B b;
public:
};
#endif
//Classe C usa a classa A e a classe B
#ifndef _C_
#define _C_
#include "classeB.h"
#include "classeA.h"
class C{
private:
A a;
B b;
public:
};
#endif
Mesmo colocando diretivas esse código não deve compilar. A diretiva #ifndef ALGO serve para que, caso ainda não tenha sido definido o ALGO entao o compilador deve 'ler' o restante caso contrário deve ignorar. Neste caso usamos essa diretiva para que o compilador nao inclua o código milhares de vezes, e sim apenas uma única vez. Então, caso ainda não tenha sido definido esse algo ele deve definir( #define ALGO) e compilar todo o código até o #endif (e seguir normalmente) e caso alguém tente usar esse código, e o compilador tente compilar novamente ele não consiguirá, porque já está definido o ALGO. Portanto o compilador deve ter compilado esse código apenas uma vez \o/
Então por que geraria a inclusão circular e não compilaria? Justamente por causa dessas diretivas. Então por que não tirá-las? Porque caso o faça, o compilador pode incluir o mesmo código indefinidas vezes causando diversos erros de compilação. Vamos supor que o compilador queira compilar a classe B primeiro. Oras, a classe B inclui a classe A, mas a classe A inclui a classe B, a qual ja foi definida, por tanto o compilador nao pode compila-la. Entao faltará a classe B para a classe A.
Exemplificando:
//Classe B usa a classe A
#ifndef _B_
#define _B_
#include "classeA.h"
#ifndef _A_
#define _A_
/*
aqui a classe B ainda não foi declarada, mas a classe A abaixo irá tentar usá-la.
*/
#incude "classeB.h"
/*o comilador aqui não pode fazer esse include,
porque há uma diretiva que não permite
portnato a classe A não pode usar a classe B*/
class A{
private:
B b;
public:
};
#endif
class B{
private:
A a;
public:
};
#endif
Qual a solução? Simples. Uma forward declaration, ou seja uma declaração antecipada. Ao invés de dizer que inclui uma classe toda (ou seja o arquivo .h ou .hh), a qual acabaria gerando uma inclusão circular, diremos apenas que há uma classe chamada 'X'. Como consequencia desse método é que devemos, usar referências, ao invés de variáveis, justamente por apenas sabermos que existe um classe, mas não como ela é definida.
solução:
//Classe B usa a classe A
#ifndef _B_
#define _B_
class A; //uma declaração antecipada.
class B{
private:
A* a; //aqui deve ser um ponteiro, porque não
//temos definido a classe A
public:
};
#endif
//Classe A usa a classe B
#ifndef _A_
#define _A_
class B; //uma declaração antecipada.
class A{
private:
B* b;//idem
public:
};
#endif
//Classe C usa a classa A e a classe B
#ifndef _C_
#define _C_
#include "classeB.h"
#include "classeA.h"
/*
como aqui, a inclusão das classes não
deve gerar a inclusão circular, podemos deixar assim.
*/
class C{
private:
A a;
B b;
public:
};
#endif
Bom, como iremos implementar esse código em algum arquivo, e precisaremos saber como são descritas as classes, devemos incluir o arquivo cabeçalho no arquivo de implementação.
Termos, então, seguindo o exemplo, tres arquivos cabeçalhos: classeA.h, classeB.h e classeC.h
e por consequencia teremos tres arquivos de implementação, que devem incluir o cabeçalho da classe declarada antecipadamente. Por exemplo
o arquivo de implementação da classe classeB.h, poderia ser:
#include "classeB.h"
#include "classeA.h"
B::metodos(){} //etc
o arquivo de implementação da classe classeA.h, poderia ser:
#include "classeA.h"
#include "classeB.h"
A::metodos(){} //etc
e o da classe classeC.h, poderia ser:
#include "classeC.h"
C::metodos(){}
Bom comentei uma solução para o problema exposto, a que na minha opnião é melhor. Dúvidas e sugestões são bem vindas xD
Nenhum comentário:
Postar um comentário