Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 13
  1. #1
    Utente di HTML.it
    Registrato dal
    Mar 2006
    Messaggi
    118

    Evitare gli annidamenti dei file header.

    Uno dei problemi riscontrati anche sul sorgente postato, sono gli annidamenti delle dichiarazioni "Include" dei file header. Se ad esempio carico il file "Main.CPP" all'interno di "ChildWin.Cpp", per poi caricare quest'ultimo in "Main.CPP", il compilatore mi dà il giusto errore. In Delphi, il problema lo risolvo scrivendo nuovamente in uno dei due file la parola chiave uses sotto implementation e dichiarando i file pas sotto questa .

    In Borland C++ invece come si può aggirare questo ostacolo?

  2. #2
    Moderatore di Programmazione L'avatar di alka
    Registrato dal
    Oct 2001
    residenza
    Reggio Emilia
    Messaggi
    24,296
    Sia in Delphi che in C++Builder, la soluzione ideale sarebbe quella di confinare ad una terza unit la "risorsa condivisa" (classe) e fare in modo che le altre due unit dipendenti la referenzino.

    Schematizzando, se A e B si referenziano a vicenda, si sposta in C le parti in comune e si fa in modo che A e B si riferiscano entrambe a C.

    Questo dovrebbe essere l'approccio da usare in Delphi, oltreché in C++Builder.
    Lo spostamento in implementation è una soluzione valida, ma solo se non se ne abusa.

    Ciao!
    MARCO BREVEGLIERI
    Software and Web Developer, Teacher and Consultant

    Home | Blog | Delphi Podcast | Twitch | Altro...

  3. #3
    In C++ basta includere gli headers nei files cpp...ad esempio se ho i files A.h, B.h, A.cpp e B.cpp, e il file B usa le definizioni di A e A usa le definizioni di B, la dipendenza la sposto nei cpp.
    Rimane il problema quando occorre usare le definizioni all'interno dell'header. Supponiamo i seguenti files:
    codice:
    File: A.h
    
    #include "B.h"
    class A
    {
    private:
      B *_owner;
    public:
      A(B *owner);
    };
    
    File B.h
    
    #include "A.h"
    class B
    {
    private:
      void doIt(A *);
    }
    ovviamente A.h deve includere B.h, ma anche B.h deve includere A.h; questo ovviamente crea il problema della ricorsione. A questo punto la soluzione è di ristrutturare il codice, togliendo la dipendenza; normalmente il 90% delle volte le ricorsioni sono dovute ad una cattiva suddivisione delle responsabilità delle classi e quindi si riescie a risolvere la dipendenza ricorsiva ottenendo anche una soluzione più pulita.
    Purtroppo a volte la dipendenza è inevitabile...allora una possibilità è quella di usare l'idioma pimpl (private implementation) che rende il codice un po' più criptico ma quando ci vuole ci vuole
    Nell'esempio di sopra usando il pimpl possiamo fare così (lo possiamo fare perchè la classe A lo usiamo nella parte privata della classe):
    codice:
    File: B.h
    
    class B
    {
    private:
      class pimpl;
      pimpl *_pimpl;
    public:
    };
    
    File: B.cpp
    
    class B::pimpl
    {
      void doIt(A *)
      {
      }
    }
    
    B::B()
     : _pimpl(new pimpl)
    {
    }
    A questo punto nella classe B dove usavamo doIt(ptrA) ora potremo usare _pimpl->doIt(ptrA). E' complicato ma a volte è l'unico modo.
    Inoltre questo ha un'altro vantaggio...rendere progetti complessi compilabili molto più velocemente...infatti le modifiche ad alcuni header richiedono solo la rigenerazione dell'obj del file C.cpp invece della ricompilazione di tutti i files che per qualche ragione includono B.h, dato che le modifiche all'interfaccia privata di B sono spostati nel file cpp; invece se li lasciamo nell'H modifiche a questa interfaccia (in fondo quella è privata proprio perchè magari la voglio cambiare in futuro) richiedono la ricompilazione di tutte le altre classi che si basano sull'interfaccia pubblica di B.

  4. #4
    Be', per evitare la ricorsione negli header si possono usare anche metodi più semplici, come la direttiva #pragma once (non supportata da tutti i compilatori) o l'uso di direttive di compilazione condizionale; ne abbiamo già parlato qui.
    Amaro C++, il gusto pieno dell'undefined behavior.

  5. #5
    Mi spiace ma nei casi che ho detto la pragma once e simili non sono di aiuto
    Se ho due header che si includono a vicenda il compilatore da (giustamente errore)...questa soluzione infatti non l'ho considerata a proposito in quanto già discussa

  6. #6
    Utente di HTML.it
    Registrato dal
    Mar 2006
    Messaggi
    118
    Ottima idea, quella di include questi header in un unico file.

    Per quanto riguarda la direttiva #pragma once non la utilizzerei solo per questioni di universalità.

  7. #7
    Originariamente inviato da fastcoder
    Mi spiace ma nei casi che ho detto la pragma once e simili non sono di aiuto
    Se ho due header che si includono a vicenda il compilatore da (giustamente errore)...questa soluzione infatti non l'ho considerata a proposito in quanto già discussa
    Be', allora si può optare per una soluzione di questo tipo:
    codice:
    File: A.h
    #define _A_
    #ifndef _B_
        #include "B.h"
    #endif
    class A
    {
    private:
      B *_owner;
    public:
      A(B *owner);
    };
    codice:
    File B.h
    #define _B_
    #ifndef _A_
        #include "A.h"
    #end if
    class B
    {
    private:
      void doIt(A *);
    }
    Amaro C++, il gusto pieno dell'undefined behavior.

  8. #8
    Utente di HTML.it
    Registrato dal
    Mar 2006
    Messaggi
    118
    Comunque la soluzione di includere più file header in un solo file condivisibile da tutti è risultata completamente inutile. Gli errori di annidamento che dà il compilatore...ho preferito optare per una soluzione "spicciola", cioè incrociare per bene gli Header.

  9. #9
    Utente di HTML.it
    Registrato dal
    Mar 2006
    Messaggi
    118
    Originariamente inviato da MItaly
    Be', allora si può optare per una soluzione di questo tipo:
    codice:
    File: A.h
    #define _A_
    #ifndef _B_
        #include "B.h"
    #endif
    class A
    {
    private:
      B *_owner;
    public:
      A(B *owner);
    };
    codice:
    File B.h
    #define _B_
    #ifndef _A_
        #include "A.h"
    #end if
    class B
    {
    private:
      void doIt(A *);
    }

    Ma quali libri di testo pubblicano tali costrutti?
    Possibile che dal 2001 che studio il C++ e costrutti simili non li avevo mai visti.
    E' una soluzione ottima, anche se fuori dalla mia portata d'immaginazione. :master:

  10. #10
    Ho aperto il mio primo libro di C++ un annetto e mezzo fa, per cui fai te... Comunque la soluzione che ti ho proposto non è presa da nessun libro di testo, è bastato pensarci un attimo.
    Amaro C++, il gusto pieno dell'undefined behavior.

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.