Domanda

Sfondo

Ho una classe astratta, qualcosa come

class IConverter{
    public:
    virtual void DoConvertion() = 0;
};

Ci saranno molte classi concrete che solo implementa DoConvertion metodo.

class TextConverter : public IConverter{
    public:
    virtual void DoConvertion(){
         // my code goes here
     }
};

class ImageConverter : public IConverter{
    public:
    virtual void DoConvertion(){
         // my code goes here
     }
};

Ci saranno molti concreta attuazione in questo modo. Ho creato un file di intestazione dire, CharacterConverter.h che ha la classe astratta iConverter .

Domanda

Dato che i miei classi concrete solo attuare il DoConvertion metodo, è necessario creare i file di intestazione separati per ogni classe concreta? Voglio dire è che ha richiesto di creare ImageConverter.h , TextConverter.h e così via per tutte le classi di cemento? Tutti questi file di intestazione sta per contenere lo stesso codice come iConverter classe astratta.

Qualche idea?

È stato utile?

Soluzione

Qualcosa si potrebbe considerare, a seconda del resto del vostro disegno, è una fabbrica, dove la classe astratta ha un metodo statico (o metodi statici più, a seconda di come si sceglie di implementare esso) che costruisce la sottoclasse appropriata e la restituisce come un iConverter *. Con questo, si può esporre solo la definizione astratta nel file di intestazione, e hanno tutte le definizioni di classe di cemento e le implementazioni in un unico file cpp con l'implementazione della classe eccellente. Questo diventa un po 'ingombrante, se i tuoi sottoclasse sono grandi, ma con classi più piccole si riduce il numero di file è necessario gestire.

Ma, come altri hanno fatto notare, è in ultima analisi, una chiamata in giudizio. Gli unici problemi di prestazioni sarebbero interessate a alla redazione; più file cpp potrebbero prendere (leggermente) più tempo per compilare e altri file header potrebbero aumentare analisi delle dipendenze. Ma non c'è alcun obbligo che ogni file di intestazione hanno un corrispondente cpp e viceversa.

Sulla base delle osservazioni, io consiglierei di una struttura come questa:

IConverter.h ==> definizione di
iConverter Converters.h ==> definizioni di tutte le sottoclassi
IConverter.cpp ==> includono IConverter.h e Converters.h, contengono attuazione iConverter funzionalità astratta (metodo factory statica e qualsiasi funzionalità ereditabili)
TextConvter.cpp, ImagerConverter.cpp, ecc ==> separati file cpp per ogni sottoclasse, ciascuna contenente IConverter.h e Converters.h

Questo consente di includere solo l'IConverter.h in ogni client che utilizzano la fabbrica e funzionalità generiche. Mettere tutte le altre definizioni in un unico colpo di testa consente di consolidare se sono tutti fondamentalmente la stessa. file cpp separati permettono di usufruire dei benefici del compilatore menzionati da Brian. Si potrebbe inline le definizioni di sottoclasse nei file di intestazione come detto, ma che in realtà non si acquista nulla. Il tuo compilatore di solito è più intelligente di te quando si tratta di ottimizzazioni come inline.

Altri suggerimenti

Non è necessario. Si tratta fondamentalmente di una chiamata in giudizio.

Se l'implementazione è semplice per ogni classe che li può mettere tutto in un unico .he una cpp

Se le implementazioni sono un po 'più a lungo, allora è probabilmente più pulito per utilizzare un file .he cpp separato per ogni.

Alcuni vantaggi di usare una diversa .h / .cpp per ogni classe:

  • Manterrà il codice organizzato e pulito
  • lavoro compilazione ridotto: Un cambiamento in una delle implementazioni non avrà bisogno di ricompilare tutti gli altri
  • tempo più veloce di compilazione: Diversi compilatori possono compilare più file contemporaneamente, come interruttore di accensione / MP Visual Studio. Con diversi file avrete un tempo di compilazione più veloce.
  • Altri file possono includere solo ciò di cui hanno bisogno invece di tutto
  • più veloce tempo di link: tempo di collegamento sarà ridotto a causa di collegamento incrementale
  • Utilizzo di controllo di versione si può guardare indietro su solo le modifiche a una particolare classe derivata, invece di dover passare attraverso tutte le modifiche apportate al file di massiccia 1 .h / cpp per scoprire che un cambiamento in una particolare classe derivata.

Probabilmente otterrete risposte in entrambe le direzioni.

Direi, per eventuali convertitori banali, avendo tutti in una sola coppia .h / cpp è sufficiente e che è eccessivo per dividere ognuno in una sola coppia. Credo che il compromesso di manutenzione di un sacco di file contro la manutenzione di un gruppo di metodi all'interno di un singolo file è valsa la pena in questo caso.

conversioni complessi probabilmente meritano le proprie coppie di file.

Sarà necessario definizioni delle classi concrete per creare oggetti, quindi avrete bisogno di mettere queste definizioni in un file .h da qualche parte. Quale file si mette loro in spetta a voi.

La migliore risposta a questo è ciò che è più facile da leggere. Un file lungo fonte sta per essere difficile per voi e altri programmatori di seguire. D'altra parte, molti piccoli (la metà schermo pieno) file di origine è altrettanto male.

Uno dei principali punti di creazione di una classe di interfaccia è così che i clienti possono essere indipendente dalla interfaccia astratta piuttosto che la concreta attuazione, e si sono quindi liberi di cambiare l'implementazione senza impattare i clienti.

Mettere le dichiarazioni di cemento nelle stesse file di intestazione come le dichiarazioni di interfaccia sconfigge questo, così ora se si cambia un dettaglio di implementazione di una classe concreta, i vostri clienti avrebbero bisogno di ri-compilazione.

Si sarebbe probabilmente meglio utilizzare fabbriche o puntatori a funzione.

Tuttavia, in un modo particolarmente sgradevole che viene in mente sta usando una macro per dichiarare le classi concrete. Ad esempio:

Nella parte inferiore della IConverter.h includere le seguenti macro

#define DECLARE_CONVERTER_CLASS(CLASS_NAME) \
class CLASS_NAME : public IConverter\
{ \
    public: \
    CLASS_NAME() {} \
    virtual void DoConversion(); \
}; \

Poi nel MyConverter1.cpp

DECLARE_CONVERTER_CLASS(MyConverter1)

virtual void MyConverter1::DoConversion()
{
    ...
}

Yuck: -)

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