Domanda

Sto cercando di creare i file di intestazione appropriati che non includono troppi altri file per tenerli puliti e per accelerare il tempo di compilazione.

Ho incontrato due problemi mentre si fa questo:

  1. dichiarazione anticipata su classi di base non funziona.

    class B;
    
    class A : public B
    {
    
        // ...
    }
    
  2. dichiarazione anticipata sulle classi STD non funziona.

    namespace std
    {
        class string;
    }
    
    class A
    {
        string aStringToTest;
    }
    

Come faccio a risolvere questi problemi?

È stato utile?

Soluzione

Il primo problema non si può risolvere.

Il secondo problema non è nulla a che fare con le classi della libreria standard. E 'perché si dichiara un'istanza della classe come un membro della vostra propria classe.

Entrambi i problemi sono dovuti alla necessità che il compilatore deve essere in grado di scoprire la dimensione totale di una classe dalla sua definizione.

Tuttavia, il compilatore può lavorare fuori la dimensione di un puntatore a una classe, anche se non ha ancora la definizione completa di esso. Quindi una possibile soluzione in questi casi è quello di avere un puntatore (o di riferimento) membro della classe che consumano.

Non molto aiuto nel caso classe di base, in quanto non sarà possibile ottenere un 'è un' rapporto.

Non è nemmeno la pena di fare per qualcosa di simile std::string. In primo luogo, si suppone di essere una vantaggiosa wrapper un buffer di caratteri, per salvare voi da fare gestione della memoria su qualcosa di così semplice. Se poi si tiene un puntatore ad esso, proprio per evitare di includere l'intestazione, probabilmente stai prendendo una buona idea troppo.

In secondo luogo (come sottolineato in un commento), std::string è un typedef per std::basic_string<char>. Quindi è necessario inoltrare dichiarare (e quindi utilizzare) che, invece, con la quale le cose temporali sono sempre molto oscuro e difficile da leggere, che è un altro tipo di costo. E 'davvero la pena?

Altri suggerimenti

Come risposto prima da Earwicker, non è possibile utilizzare in avanti dichiarazioni in uno qualsiasi di questi casi, come il compilatore ha bisogno di conoscere la dimensione della classe.

È possibile utilizzare solo una dichiarazione anticipata in una serie di operazioni:

  • funzioni che richiedono la classe in avanti definite come parametri o la restituisce dichiarando
  • dichiarando puntatori membri o riferimenti alla classe dichiarata in avanti
  • dichiarazione di variabili statiche del tipo avanti dichiarato nella definizione di classe

Non è possibile utilizzarlo per

  • dichiarare un attributo membro del tipo specificato (compilatore richiede dimensioni)
  • definire o creare un oggetto del tipo o eliminarlo
  • chiamare qualsiasi metodo statico o membro della classe o accedere a qualsiasi membro o attributo static

(ho dimenticato qualcuno?)

tener conto che dichiara un auto_ptr non è lo stesso che dichiarare un puntatore prime, dal momento che l'istanza auto_ptr cercherà di eliminare il puntatore quando si va fuori del campo di applicazione e la cancellazione richiede la dichiarazione completa del tipo. Se si utilizza un auto_ptr a tenere un tipo in avanti dichiarato si dovrà fornire un distruttore (anche se vuoto) e definirlo dopo la dichiarazione della classe completo è stato visto.

Ci sono anche alcune altre sottigliezze. Quando si inoltra dichiarare una classe, si indica al compilatore che sarà una classe. Ciò significa che non può essere un enum o un typedef in un altro tipo. Questo è il problema che si stanno ottenendo quando si tenta di inoltrare dichiarare std::string, in quanto è un typedef di una specifica istanza di un modello:

typedef basic_string<char> string; // aproximate

Per inoltrare dichiarare stringa che si avrebbe bisogno di trasmettere dichiarare il modello basic_string e quindi creare il typedef. Il problema è che la norma non indica il numero di parametri che basic_string modello prende, si afferma solo che se ci vuole più di un parametro, ci resto dei parametri deve avere un tipo predefinito cosicché l'espressione sopra compila. Ciò significa che non esiste un modo standard per l'ora dichiarare il modello.

Se, d'altra parte si desidera inoltrare dichiarare un modello non-standard (non STL, che è) si può fare per tutto il tempo come si fa conoscere il numero di parametri:

template <typename T, typename U> class Test; // correct
//template <typename T> class Test; // incorrect even if U has a default type

template <typename T, typename U = int> class Test {
   // ...
};

Alla fine, il consiglio che è stato dato a voi da Roddy:. Avanti dichiarare per quanto è possibile, ma per scontato che alcune cose devono essere inclusi

Si sta cercando troppo difficile da risolvere qualcosa che in realtà non è un problema. Utilizzare i file header necessari, e ridurre - per quanto possibile - l'obbligo per loro. Ma non provate e portarlo agli estremi perché si riesce.

In alcuni casi, l'idioma Pimpl può aiutare, ma non qui.

In entrambi i casi il compilatore ha bisogno di conoscere la dimensione del tipo. Pertanto, una dichiarazione anticipata non sarà sufficiente. Una classe di base potrebbe aggiungere membri o richiedere una tabella virtuale. Il membro della stringa richiederebbe la dimensione della classe da aumentare per memorizzare la dimensione della classe string STL.

Inoltra dichiarando classi STL è spesso sconsigliabile poiché le implementazioni sono comunemente istanze dei modelli espliciti che accelerare la compilazione.

Per le tue classi di base, è necessario avere la definizione del tipo completo, non solo una dichiarazione. intestazioni tipo derivato dovranno # include l'intestazione per le loro classi di base.

Per le classi del namespace std, è necessario includere la corretta intestazione - in questo caso - e quindi effettuare una delle 3 cose:

  1. Completamente qualificare il tipo: std :: string aStringToTest

  2. Mettere una dichiarazione secondo per soli quel tipo: utilizzando std :: string;

  3. Mettere in una dichiarazione di utilizzare per la std namespace: using namespace std;

> Sembra che la dichiarazione in avanti è inutile per le classi di base e le classi STL.

Correzione ... dichiarazione anticipata è inadeguato per classi base e membro oggetto. (Non è "inutile", è "inapplicabile".)

Una classe di base deve essere dichiarata (non in avanti dichiarato) quando viene dichiarata come una classe basata su un'altra classe.

Un membro oggetto deve essere dichiarata (non in avanti dichiarata) quando viene dichiarato da un'altra classe, o come parametro o come valore di ritorno. NOTA: per riferimento o puntatore non avere quel vincolo

.

Correzione ... dichiarazione anticipata di classi STL è - secondo ISO 14882 - un comportamento indefinito. http://www.gotw.ca/gotw/034.htm

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top