Newsgroup: it.comp.lang.c++
Titolo: #include incrociati

Salve,
ho questa situazione, 2 classi, una detta A, l'altra B.
Nella classe A viene dichiarato un puntatore ad un tipo B, nel file della 
classe B viene dichiarato un puntatore ad un tipo A:
---------
// file "a.h"
class A
{
...
B* b;
};
// file "b.h"
class B
{
...
A* a;
};
---------
Il compilatore mi dava dei problemi in quanto mi diceva che il tipo A non 
era dichiarato in B e viceversa.
Ho risolto trovando su google un esempio, modificando i file in questo modo:
---------
// file "a.h"
class B; // <--------
class A
{
...
B* b;
};
// file "b.h"
class A; // <--------
class B
{
...
A* a;
};
---------
Funziona ma che senso ha? E' corretto o è solo un escamotage un pò strano 
per far funzionare il tutto?
Saluti, 

 per far funzionare il tutto?
Il punto è che per dichiarare un puntatore, o un riferimento ad una 
classe, il compilatore non ha bisogno di sapere nulla della classe, se 
non che esiste. Dunque la dichiarazione
class A;
significa proprio questo: A è una classe, non meglio specificata.
E.


Susate, ma questa soluzione funziona anche volessi anche usare dei
metodi di A e di B tramite quei puntatori?
In questo caso al compilatore non basterebbe più sapere che le classi
esistono

 esistono
No, se vuoi usare i metodi hai bisogno della definizione completa della 
classe. Ma l'utilizzo dei metodi tipicamente avviene nel file .c non 
nello header .h
E.

 E.

probabilmente sbaglierò[...]
Quindi probabilmente è meglio che prima provi e poi dai suggerimenti.

Andrea Laforgia ha scritto:

dunque, ho provato il discorso degli include reciproci con 
dichiarazioni anticipate senza definizione.
Il compilatore (VCPP 6) me la da buona (cosa di cui dubitavo),
ma mi stanga il linker (cosa che non pensavo affatto), dicendo :
scemo_00.obj : error LNK2001: unresolved external symbol 
"public: int __thiscall A::FunzA(int,int)" (?FunzA@A@@QAEHHH@Z)
scemo_00.obj : error LNK2001: unresolved external symbol 
"public: int __thiscall B::FunzB(int,int)" (?FunzB@B@@QAEHHH@Z)
di seguito metto i sorgenti che ho provato, grazie 
all'incoraggiamento del prode LaForgia,
mi sono voluto levare lo scrupolo di capire se e quanto avevo 
scritto una cavolata. In effetti, oltre a capire che non funge, 
non penso di aver capito la difficoltà, dato che le rogne me le 
solleva il linker che imho, a quel punto, avrebbe dovuto sapere 
vita morte e miracoli delle due funzioni chiamate anzitempo 
rispetto alla definizione.
Come mai succede questo ? Vorrei capire in cosa era sbagliata la 
supposizione che sarebbe stato possibile compilare con 
riferimenti a una funzione ancora da definire, e risulvere 
l'indirizzo a linking ...
ciao
soviet_mario
-sorgenti-
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
file scemo_AA_H.H
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
#ifndef A_A
#define A_A
class A {
	int Silly_A;
public:
	int FunzA (int, int);
};
#endif // A_A
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
file scemo_BB_H.H
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
#ifndef B_B
#define B_B
class B {
	int Silly_B;
public:
	int FunzB (int, int);
};
#endif // B_B
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
file scemo_AA_CPP.CPP
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
#include "stdafx.h"
#include "D:\SourceCode_Vb_5\Prove_generali\scemo_00\scemo_AA_H.H"
#include "D:\SourceCode_Vb_5\Prove_generali\scemo_00\scemo_BB_H.H"
int class A :: FunzA (int uno, int due)
{
	B tempB;
	return (tempB . FunzB (uno, due) - (uno * due));
};
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
file scemo_BB_CPP.CPP
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
#include "stdafx.h"
#include "D:\SourceCode_Vb_5\Prove_generali\scemo_00\scemo_AA_H.H"
#include "D:\SourceCode_Vb_5\Prove_generali\scemo_00\scemo_BB_H.H"
int class B :: FunzB (int uno, int due)
{
	A tempA;
	return (tempA . FunzA (uno, due) + (uno * due));
};
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
file scemo_00.cpp
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// scemo_00.cpp : Defines the entry point for the console 
application.
//
#include "stdafx.h"
#include "D:\SourceCode_Vb_5\Prove_generali\scemo_00\scemo_AA_H.H"
#include "D:\SourceCode_Vb_5\Prove_generali\scemo_00\scemo_BB_H.H"
int main(int argc, char* argv[])
{
	A aaa;
	B bbb;
	int N1 = 5, N2 = 8;
	printf("%d %d \n", aaa . FunzA (N1, N2),  bbb . FunzB (N1, N2));
	return 0;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

 ritorno e tipi dei parametri.
Non puoi definire solo un singolo metodo, ma tutta la classe. Ma questo 
non crea usualmente problemi (se non con le funzioni inline). Il codice 
che hai scritto nell'altro post fa proprio questo e dovrebbe funzionare 
(non capisco perché ti dia errore).
Piů semplicemente lo schema č:
class A;
class B;
class A {
	B *ptr;
public:
	void set(B *);
	/* altri metodi e campi di A */
};
class B {
	/* dichiarazione completa di B*/
};
void A::set(B* p) {
	ptr=p;
	/* qui posso usare tutti i metodi di B */
}
main() {
	A a;
	B b;
	a.set(&b);
}
E.

E nel caso di template di classe come si fa?
Sbaglio o definizione e implementazione devono essere in un unico file?

 Sbaglio o definizione e implementazione devono essere in un unico file?
Puoi dare prima tutte le dichiarazioni (quella che tu chiami 
definizioni) e poi tutte le definizioni (quelle che tu chiami 
implementazioni). Non ci sono particolari difficoltà.
Le difficoltà con le classi che si autorefernziano circolarmente è che 
senza accorgersene si rischia di fare degli #include ricorsivi come in:
// file A.h
#include "B.h"
class A {
	B *ptr;
};
// file B.h
#include "A.h"
class B {
	A *ptr;
};
credo che in una situazione del genere il compilatore dovrebbe darti un 
errore sensato. Se però (come s'usa) ogni file header ha un controllo 
sull'unicità dell'inclusione, tipo:
// file A.h
#ifndef A_H
#define A_H
#include "B.h"
// ....
// ....
#endif
e' più difficile identificare l'errore.
E.