2011-11-02 13 views
10

In C++ e Objective-C, ho preso l'abitudine di dichiarare in avanti tutte le classi necessarie che non devono essere definite nell'intestazione e quindi di importare i file di intestazione che definiscono tali classi nei file di origine, se necessario.Svantaggi della dichiarazione anticipata?

C'è mai una situazione in cui questa non sarebbe una buona idea?

(So che il grande svantaggio della dichiarazione di inoltro è l'usabilità limitata di un tipo incompleto. Ai fini di questa domanda, supponiamo che nell'intestazione sia necessario utilizzare solo la classe dichiarata avanti come tipo incompleto.)

+17

Meno possibilità di bere caffè durante una costruzione completa? –

risposta

6

A volte si può cambiare la semantica del programma sottilmente senza sollevare eventuali errori

class Foo; 

template < typename T> 
struct Trait 
{ 
    static const int MY_TYPE = -1; 
}; 

// Lets say this is Foo.h 
//class Foo 
//{ 
//}; 
//template<> 
//struct Trait<Foo> 
//{ 
// static const int MY_TYPE = 1; 
//}; 

void TestFunction(Foo& f) 
{ 
    std::cout << Trait<Foo>::MY_TYPE << std::endl; 
} 

Si consideri il codice di cui sopra e il codice commentato vive in un colpo di testa. Se l'intestazione è inclusa, TestFunction stampa 1 altrimenti -1

+0

+1 .. Probabilmente più applicabile del mio commento sapendo quello che so ora del processo di pensiero dell'OP. – Steve

+0

Cose interessanti. Questo è il genere di cose di cui ero curioso. – Luke

3

Uno svantaggio potrebbe essere la mancanza di occultamento/incapsulamento delle informazioni.

Preferisco avere il file di intestazione più minimale possibile. Significa che non sono obbligato a continuare a supportare così tante funzioni. Se voglio cambiare qualcosa, e che qualcosa non è stato esposto nell'intestazione pubblica, ci sono molte più possibilità che io possa cambiarlo internamente alla classe senza influenzare nessun altro.

EDIT:

Luca ha chiesto per un esempio, ecco ya go:

Supponiamo di avere una classe chiamata Car. E, l'unica cosa per cui lo hai costruito era ottenere dal punto A al punto B. Io personalmente preferirei mantenere il mio file di intestazione in: una classe chiamata Car e un metodo chiamato Drive. Dal modo in cui hai formulato la tua domanda ("tutte le classi che posso") mi aspetterei di trovare classi come "DieselEngine", "PetrolEngine", "HybidEngine" e simili nel tuo file di intestazione. Il problema con questo è che altre persone che lavorano al tuo progetto (o, tu, nel tempo) iniziano a usare quelle classi esposte. Ora, due anni dopo, decidi "Hrm ... che la classe PetrolEngine mi stia davvero causando problemi, penso che lo rimuoverò e lo sostituirò interamente con la HybridEngine nella mia classe Car" - beh, ora PetrolEngine è incluso in 100 altri file per motivi che non capisci - e ora sei costretto a tenere PetrolEngine in giro (e lavorare come al solito) per tutti quegli altri ragazzi che lo hanno usato in alcuni dicono che non sei proprio sicuro di - perché non avevi un solido "contratto" di lavoro per come volevi che quella classe fosse usata in primo luogo. Era un dettaglio di implementazione di ciò che volevi davvero realizzare: costruire un'auto.

EDIT per discutere commenti su informazioni nascondere:

Se tutto quello che stai facendo è rigorosamente in avanti dichiarando il nome della classe/struct - beh, credo vorrei chiedere "perché" di nuovo. Se sono un utente del tuo file di intestazione e delle classi, e non posso realmente fare nulla con quella classe - e non è esposto come parametro o tipo di ritorno dell'API della tua classe principale - allora perché esporlo a tutti ?

Se lo si utilizza per i controlli di sicurezza del tipo in fase di compilazione per strutture di dati opache - bene - questa è una cosa. Ma il modo in cui hai formulato la tua domanda mi ha fatto sembrare come che tutto il è andato nel file di intestazione come una cosa ovvia.

+0

Non sono sicuro di sapere cosa intendi. Potresti fare un esempio? – Luke

+4

Questa tecnica non potrebbe migliorare la protezione delle informazioni? Ci sono molte meno informazioni in una dichiarazione anticipata rispetto a una dichiarazione completa. –

+2

Puoi spiegare in che modo le dichiarazioni anticipate interrompono l'incapsulamento? Mi sembra che fornire solo il nome della classe nasconda molte più informazioni che fornire la definizione completa. –

0

Nessuno, per quanto ne so. L'unico svantaggio, che hai già trattato, riguarda l'uso di tipi incompleti. Dal momento che dici che non ci saranno usi che richiedono tipi completamente definiti, tu stai bene, immagino.

0

Le dichiarazioni di inoltro sono preferite per l'inclusione del file completo se non è necessaria l'intera definizione della classe nell'intestazione.L'unico svantaggio a cui posso pensare è stato già postato come commento da @Stephen Darlington che avrei dato 10 voti se potessi. :)

0

Uno svantaggio è la potenziale perdita di memoria nei tipi dichiarati in avanti. Vedi this question per maggiori dettagli. Problema di compilatori Microsoft warning C4150: deletion of pointer to incomplete type 'SomeType'; no destructor called in questo caso.

+2

Non è un problema con un compilatore reale. –

2

Le dichiarazioni di inoltro possono essere applicate a molte cose: classi, funzioni, variabili/costanti globali (utilizzando extern) e in C++ 11, enumerazioni.

Lo svantaggio principale, per quanto posso vedere, è la ridondanza, poiché la ridondanza introduce più possibilità di errori, tuttavia ciò si applica in modo molto diverso a seconda di ciò che si sta dichiarando.

Se si ha un errore con la dichiarazione di inoltro di una classe, globale o enum, il compilatore deve prenderlo (sì!).

Se si ha un errore nella dichiarazione di una funzione, in C++ è stato semplicemente creato un sovraccarico (oups!).

Direi quindi che non vi è alcun reale svantaggio nell'inoltrare classi, globali o enumerazioni; tuttavia, quando si tratta di funzioni, è meglio se ci si attiene a #include, è sempre possibile creare intestazioni che raggruppano le funzioni correlate per evitare di creare troppi file.

0

È probabilmente soprattutto una questione di leggibilità per i colleghi che dovrà continuare il lavoro di codifica.