|
|
|
![]() |
|
Strumenti |
![]() |
#1 |
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
[C++] dipendenze incrociate & compilazione
Se la classe A ha un riferimento alla classe B e la classe B ha un riferimento alla classe A
Codice:
//A.cpp class A { private: A a; } //B.cpp class B { private: B b; }
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me! |
![]() |
![]() |
![]() |
#2 |
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
Penso di aver risolto con due forward declaration... ma penso è già un termine forte.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me! |
![]() |
![]() |
![]() |
#4 |
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
io suppongo che tu abbia sostanzialmente provato a fare una cosa del genere:
Codice:
class A; class B; class A { private: B b; } class B { private: A a; } memore della tua ammirevole esperienza in Java ![]() ![]() quindi in sostanza io direi: Codice:
class A; class B; class A { private: B *b; } class B { private: A *a; } ![]() Ultima modifica di 71104 : 27-05-2007 alle 18:19. |
![]() |
![]() |
![]() |
#5 |
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
![]() ![]()
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me! |
![]() |
![]() |
![]() |
#6 |
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
:|
|
![]() |
![]() |
![]() |
#7 |
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
Toglimi una curiosità perchè qui navigo veramente a vista.
Le classi A e B si conoscono a vicenda. Non posso includere in A il sorgente di B e includere il B il sorgente di A perchè il compilatore si arrotola, cosa peraltro evidente se si considera come funziona l'include. Orbene, posso usare la dichiarazione posticipata sia in A che in B rispettivamente di B ed A. Risolve l'intoppo. De problem is: poichè a dichiarazione posticipata sembra generare un tipo temporaneo incompleto non riesco ad invocare delle funzioni membro di A o B da B o A. Cioè (pseudo): Codice:
class A private: A a; public: void pippo() {} Codice:
class A; class B private A b; public: void qui() { a->pippo(); << ciccia! pippo non esiste. } E' possibile aggiungere delle funzioni membro alla dichiarazione posticipata?
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me! Ultima modifica di PGI-Bis : 28-05-2007 alle 11:38. |
![]() |
![]() |
![]() |
#8 |
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
ORRORE, non bisogna mai includere files sorgenti
![]() la direttiva #include serve ad includere solamente headers; può essere usata teoricamente per includere sorgenti, ma non si deve fare. inoltre la dichiarazione della classe deve essere separata dall'implementazione, ed in tal modo hai una sorta di dichiarazione forward che include tutti i metodi, i quali però sono implementati più avanti. la dichiarazione della classe deve stare nell'header, e l'implementazione nei sorgenti .cpp. in pratica ti devono uscire fuori quattro files: a.h: Codice:
#ifndef __A_H__ #define __A_H__ #include "b.h" class A { private: B *b; public: void pippo(); }; #endif Codice:
#ifndef __B_H__ #define __B_H__ #include "a.h" class B { private: A *a; public: void pluto(); }; #endif Codice:
#include "a.h" void A::pippo() { . . . b->pluto(); } Codice:
#include "b.h" void B::pluto() { . . . a->pippo(); } 1) gli #ifndef iniziali in ciascun header servono a proteggere dall'inclusione multipla, la quale provocherebbe la ridichiarazione dei simboli dichiarati dall'header. 2) questo esempio di codice è sintatticamente corretto, però si "arrotola" lo stesso a runtime (un metodo chiama l'altro). 3) cosa importante: quando passi la lista dei files da compilare al compilatore non passargli gli headers, ma solamente i sorgenti .cpp (ed eventualmente, se ne hai, i sorgenti .c). in questo caso dovresti richiamanre semplicemente: gcc [opzioni varie] a.cpp b.cpp Ultima modifica di 71104 : 28-05-2007 alle 12:26. |
![]() |
![]() |
![]() |
#9 |
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
ah, un'altra cosa: copiando dal tuo sorgente ho finito per dichiarare come private i due metodi pippo e pluto, ma in realtà è ovvio che ciascuno di essi deve stare in una sezione public affinché l'altra classe possa chiamarlo
![]() ora correggo il post precedente. edit - si buonanotte, mi ero anche scordato di dichiarare a e b come puntatori ![]() |
![]() |
![]() |
![]() |
#10 |
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
in alternativa un'altra soluzione valida avrebbe potuto essere questa:
ab.h: Codice:
#ifndef __AB_H__ #define __AB_H__ class B; // ad A serve la dichiarazione forward, a B invece no class A { private: B *b; public: void pippo(); }; class B { private: A *a; public: void pluto(); }; #endif Codice:
#include "ab.h" void A::pippo() { . . . b->pluto(); } void B::pluto() { . . . a->pippo(); } |
![]() |
![]() |
![]() |
#11 |
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
Che tu sappia non c'è un compilatore che sia in grado di risolvere da solo queste beghe? Ora uso g++.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me! |
![]() |
![]() |
![]() |
#12 | |
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
Quote:
![]() ![]() |
|
![]() |
![]() |
![]() |
#13 |
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
tutto questo parlare di C++ traviato mi ha fatto venire in mente quello che di fatto è un'implementazione di C++ traviato, ovvero il C#
![]() il C#, similmente a Java, ha un sistema di packaging che si gestisce tramite import anziché #include, e gli oggetti viaggiano da una parte all'altra del programma sempre e solo per copia di riferimento (come in Java). hai anche a disposizione un garbage collector nonché l'enorme potenza della piattaforma .NET, la quale (se ricordo bene) ti mette a disposizione (se vuoi) le interfacce API Win32. in altre parole, sei proprio sicuro di dover programmare in C++? ![]() |
![]() |
![]() |
![]() |
#14 |
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
Non so in C# ma in Java la dipendenza circolare tra unità di compilazione è oggetto di un esplicito disposto delle specifiche (JLS 3, 7.3). Non credo che abbia a che fare con i puntatori. Comunque sia, la faccio superchiara:
Codice:
//A.cpp class A { private: B* b; public: void call() { b->call(); } } Codice:
//B.cpp class B { private: A* a; public: void call() { a->call(); } } ![]() ![]()
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me! |
![]() |
![]() |
![]() |
#15 | |
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
Quote:
![]() per compilarla con le minori modifiche possibili dovresti #includere in ciascuno l'altro, e la cosa provocherebbe un'inclusione circolare dalla quale l'#ifndef ti salverebbe, ma non riuscirebbe a farti compilare con successo. ipotizza di scrivere questo: a.cpp Codice:
#ifndef __A_CPP__ #define __A_CPP__ #include "b.cpp" class A { private: B* b; public: void call() { b->call(); } } #endif Codice:
#ifndef __B_CPP__ #define __B_CPP__ #include "a.cpp" class B { private: A* a; public: void call() { a->call(); } } #endif a.cpp Codice:
#ifndef __A_CPP__ #define __A_CPP__ #ifndef __B_CPP__ #define __B_CPP__ #include "a.cpp" // questo non lo espando perché a questo punto __A_CPP__ risulta definita: a.cpp NON viene incluso un'altra volta class B { private: A* a; public: void call() { a->call(); } } #endif class A { private: B* b; public: void call() { b->call(); } } #endif Codice:
class B { private: A* a; // A...? che cos'e' A? public: void call() { a->call(); } } class A { private: B* b; public: void call() { b->call(); } } ![]() come fai allora a risolvere?? la spiegazione è al post #8: devi necessariamente separare la dichiarazione di una classe dalla sua implementazione. la dichiarazione di una classe ti permette di fatto di avere quella che concettualmente è una dichiarazione forward che definisce già tutti i prototipi dei metodi. è praticamente quello che cercavi al post #7 ![]() Ultima modifica di 71104 : 28-05-2007 alle 20:12. |
|
![]() |
![]() |
![]() |
#16 |
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
Benissimo. Appurato che coi cpp non è possibile compilare quella roba, passiamo agli h. Che fa rima con cacca e non è un caso.
Abusando della tua pazienza ti chiederei un ultima cosa. Mi confermi che questo: Codice:
#ifndef A_H #define A_H #include "B.h" class A { private: B *b; public: A(); }; #endif Codice:
#ifndef B_H #define B_H #include "A.h" class B { private: A* a; public: B(); }; #endif Codice:
#include "A.h" A::A() { b = 0; } Codice:
#include "B.h" B::B() { a = 0; } ![]() g++ *.cpp Codice:
In file included from A.h:3, from A.cpp:1: B.h:6: error: ISO C++ forbids declaration of `A' with no type B.h:6: error: expected `;' before '*' token In file included from B.h:3, from B.cpp:1: A.h:6: error: ISO C++ forbids declaration of `B' with no type A.h:6: error: expected `;' before '*' token ![]()
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me! |
![]() |
![]() |
![]() |
#17 |
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
urka, grazie per avermi fatto notare che non compila: praticamente hai fatto quello che ti avevo detto al post #8, ma ho detto na cazzata perché separare la dichiarazione dall'implementazione non basta a risolvere il problema ^^
le soluzioni servono entrambe: devi sia usare gli headers sia le dichiarazioni forward, ed inoltre a questo punto non è più necessario includere nulla dagli headers, ma puoi includere direttamente tutto solo dai sorgenti. in poche parole questo dovrebbe risolvere tutto: a.h: Codice:
#ifndef A_H #define A_H class B; class A { private: B *b; public: A(); ~A(); void call(); }; #endif Codice:
#ifndef B_H #define B_H class A; class B { private: A *a; public: B(); ~B(); void call(); }; #endif Codice:
#include "a.h" #include "b.h" A::A() { b = new B(); b->call(); } A::~A() { delete b; } void A::call() { } Codice:
#include "a.h" #include "b.h" B::B() { a = new A(); a->call(); } B::~B() { delete a; } void B::call() { } |
![]() |
![]() |
![]() |
#18 |
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
ok, ho provato a compilarlo da me e stavolta sintatticamente è corretto: compila ma non linka (ovviamente ci manca il main). una roba del genere comunque non la eseguire perché se istanzi una di quelle due classi inizi a chiamare i due costruttori a ruota e fai stack overflow
![]() fammi sapere se hai ancora problemi. |
![]() |
![]() |
![]() |
#19 |
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
![]() ![]() Certo che se il deitel o lo strappentroff si dedicassero un po' meno all'apologia del puntatore e un po' più alle questione concrete gioverebbe e non poco.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me! |
![]() |
![]() |
![]() |
#20 | ||
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
Quote:
sarà che dicono che è il linguaggio più complesso ![]() ma toglimi la curiosità: perché stai programmando in C++? è per lavoro? Quote:
![]() |
||
![]() |
![]() |
![]() |
Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 19:37.