SamL
(usa XUbuntu)
Enviado em 27/05/2024 - 10:44h
Faz muitos dias mas vou rewsponder mesmo assim.
O nome disso é dependencia circular, no java o javac faz a parada de resolver pelo programador e por isso não tem todo o trabalho que tem em linguagem como no C.
Pra resolver isso vc terá de colocar cada class numa unidade de compilação (compiler unit) e ai compilar em separado e então juntar tudo no executável final.
Observe também que o construtor padrão de cada classe está sendo chamado e é melhor transformá-las em ponteiro.
Uma unidade de compilação nada mais é que um módulo, vc coloca a classe num headerque é um arquivo.h e o código real dela vai dentro de um arquivo.cpp e então vc compila com:
g++ -c classeA.cpp
g++ -c classeB.cpp
g++ -c main.cpp
Vai ser gerado 3 arquivos: classeA.o classeB.o e main.o
Pra juntar tudo num executável basta fazer:
g++ -o main classeA.o classeB.o main.o
Veja como é um header pra uma unidade de compilação:
Salve como arquivo classeA.h
#ifndef CLASSE_A //include guard, alguns compiladores modernos usam #pragma once
#define CLASSE_A
//declarando B antes de B aparecer no código
//observe que o B aqui não pode ser usado código diretamente no header
//exemplo: não dá pra fazer ClasseB b porque ai vc estará chamando o construtor padrão de ClasseB
//chamando ele antes mesmo de ClasseB vir a existir
class ClasseB;
class ClasseA {
private:
ClasseB *aClasseB; //ponteiro Link
public:
ClasseA();//construtor padrão
//Ativa o link
void setAClasseB(ClasseB *b);
};
#endif
Salve como arquivo classeA.cpp
#include "classeA.h"
ClasseA::ClasseA(){
aClasseB = nullptr;
}
//Ativa o link
void ClasseA::setAClasseB(ClasseB *b){
aClasseB = b;
}
Salve como arquivo header classeB.h
#ifndef CLASSE_B //include guard, alguns compiladores modernos usam #pragma once
#define CLASSE_B
//declarando ClasseA antes de ClasseA aparecer no código
//observe que o A aqui não pode ser usado código diretamente no header
//exemplo: não dá pra fazer "ClasseA a;" porque ai vc estará chamando o construtor padrão de ClasseA
//chamando ele antes mesmo de ClasseA vir a existir
class ClasseA;
class ClasseB {
private:
ClasseA *aClasseA; //ponteiro Link
public:
ClasseB();//construtor padrão
//Ativa o link
void setAClasseA(ClasseA *a);
};
#endif
Salve como arquivo classeB.cpp
#include "classeB.h"
ClasseB::ClasseB(){
aClasseA = nullptr;
}
//Ativa o link
void ClasseB::setAClasseA(ClasseA *a){
aClasseA = a;
}
Agora o main:
#include "classeA.h"
#include "classeB.h"
int main () {
ClasseA a;
ClasseB b;
//seta a ClasseB em ClasseA
a.setAClasseB(&b);
//seta a ClasseA em ClasseB
b.setAClasseA(&a);
return 0;
}
Observe que ao criar uma unidade de compilação pra cada classe, vc pode incluir o header dela
dentro do outro arquivo cpp :
Exemplo, se dentro do arquivo classeB.cpp vc quiser fazer uma chamada a alguma função de aClasseA, basta chamar normalmente pelo ponteiro, mas pra funcionar é preciso incluir o header classeA.h dentro do módulo classeB.cpp.
Se modificar qualquer um desses arquivo é necessário recompilar somente ele. Exemplo, caso modifique o main, então, reexecute o:
g++ -c main.cpp
seguido pelo:
g++ -o main ClasseA.o ClasseB.o main.o
Use um makefile para automatizar o processo ou aprenda sobre o cmake e economize tempo.
https://nerdki.blogspot.com/ acessa ai, blog dedicado Paranóia!
https://github.com/cpusam com o bug fix vem a perfeição!