Domanda

Come ho capito, il linguaggio del pimpl esiste solo perché C ++ ti obbliga a mettere tutti i membri della classe privata nell'intestazione. Se l'intestazione dovesse contenere solo l'interfaccia pubblica, teoricamente, qualsiasi modifica nell'implementazione della classe non avrebbe richiesto una ricompilazione per il resto del programma.

Quello che voglio sapere è perché C ++ non è progettato per consentire tale praticità. Perché è necessario che le parti private di una classe vengano visualizzate apertamente nell'intestazione (non è previsto un gioco di parole)?

È stato utile?

Soluzione

Questo ha a che fare con la dimensione dell'oggetto. Il file h viene utilizzato, tra le altre cose, per determinare la dimensione dell'oggetto. Se i membri privati ??non vi sono indicati, allora non sapresti quanto è grande un oggetto nuovo.

È possibile simulare, tuttavia, il comportamento desiderato nel modo seguente:

class MyClass
{
public:
   // public stuff

private:
#include "MyClassPrivate.h"
};

Questo non impone il comportamento, ma estrae le cose private dal file .h. Sul lato negativo, questo aggiunge un altro file da mantenere. Inoltre, in Visual Studio, l'intellisense non funziona per i membri privati ??- questo potrebbe essere un vantaggio o un difetto.

Altri suggerimenti

Penso che ci sia confusione qui. Il problema non riguarda le intestazioni. Le intestazioni non fanno nulla (sono solo modi per includere bit comuni di testo sorgente tra diversi file di codice sorgente).

Il problema, per quanto ce n'è uno, è che le dichiarazioni di classe in C ++ devono definire tutto, pubblico e privato, che un'istanza deve avere per funzionare. (Lo stesso vale per Java, ma il modo in cui funziona il riferimento alle classi compilate esternamente rende superfluo l'uso di qualcosa come le intestazioni condivise.)

È nella natura delle comuni tecnologie orientate agli oggetti (non solo quella C ++) che qualcuno ha bisogno di conoscere la classe concreta utilizzata e come utilizzare il suo costruttore per fornire un'implementazione, anche se si sta utilizzando solo parti pubbliche. Il dispositivo in (3, sotto) lo nasconde. La pratica in (1, sotto) separa le preoccupazioni, che tu lo faccia (3) o meno.

  1. Utilizza le classi astratte che definiscono solo le parti pubbliche, principalmente i metodi, e lascia che la classe di implementazione erediti da quella classe astratta. Quindi, usando la solita convenzione per le intestazioni, c'è un abstract.hpp che è condiviso in giro. Esiste anche un Implement.hpp che dichiara la classe ereditata e che viene trasmessa solo ai moduli che implementano i metodi di implementazione. Il file Implement.hpp #include " abstract.hpp " per l'uso nella dichiarazione di classe che fa, in modo che vi sia un unico punto di manutenzione per la dichiarazione dell'interfaccia astratta.

  2. Ora, se vuoi imporre il nascondimento della dichiarazione della classe di implementazione, devi avere un modo per richiedere la costruzione di un'istanza concreta senza possedere la specifica e completa dichiarazione di classe: non puoi usare new e tu non è possibile utilizzare istanze locali. (Puoi eliminare però.) L'introduzione di funzioni di supporto (inclusi metodi su altre classi che forniscono riferimenti a istanze di classe) è il sostituto.

  3. Insieme o come parte del file di intestazione utilizzato come definizione condivisa per la classe / interfaccia astratta, includere le firme di funzione per le funzioni di supporto esterne. Queste funzioni dovrebbero essere implementate in moduli che fanno parte delle implementazioni di classi specifiche (in modo che vedano la dichiarazione di classe completa e possano esercitare il costruttore). La firma della funzione helper è probabilmente molto simile a quella del costruttore, ma di conseguenza restituisce un riferimento all'istanza (questo proxy del costruttore può restituire un puntatore NULL e può anche generare eccezioni se ti piace quel genere di cose). La funzione helper costruisce una particolare istanza di implementazione e la restituisce cast come riferimento a un'istanza della classe astratta.

Missione compiuta.

Oh, la ricompilazione e il ricollegamento dovrebbero funzionare nel modo desiderato, evitando la ricompilazione dei moduli chiamanti quando cambia solo l'implementazione (poiché il modulo chiamante non esegue più alcuna allocazione di memoria per le implementazioni).

State tutti ignorando il punto della domanda -

Perché lo sviluppatore deve digitare il codice PIMPL?

Per me, la migliore risposta che posso trovare è che non abbiamo un buon modo per esprimere il codice C ++ che ti consente di operare su di esso. Ad esempio, riflessione in fase di compilazione (o pre-processore o altro) o un codice DOM.

C ++ ha davvero bisogno che uno o entrambi questi siano disponibili per uno sviluppatore per fare meta-programmazione.

Quindi potresti scrivere qualcosa del genere nel tuo pubblico MyClass.h:

#pragma pimpl(MyClass_private.hpp)

E poi scrivi il tuo generatore di wrapper davvero banale.

Qualcuno avrà una risposta molto più dettagliata di me, ma la risposta rapida è duplice: il compilatore deve conoscere tutti i membri di una struttura per determinare i requisiti di spazio di archiviazione e il compilatore deve conoscere l'ordinamento di quei membri per generare offset in modo deterministico.

La lingua è già abbastanza complicata; Penso che un meccanismo per dividere le definizioni di dati strutturati nel codice sarebbe un po 'disastroso.

In genere, ho sempre visto classi di politiche utilizzate per definire il comportamento dell'implementazione in un Pimpl-maniera. Penso che ci siano alcuni vantaggi aggiuntivi nell'uso di un modello di politica: più facile da scambiare implementazioni, può facilmente combinare più implementazioni parziali in una singola unità che consente di suddividere il codice di implementazione in unità funzionali, riutilizzabili, ecc.

Può essere perché la dimensione della classe è richiesta quando si passa la sua istanza per valori, aggregandola in altre classi, ecc?

Se il C ++ non supportasse la semantica del valore, sarebbe andato bene, ma lo è.

Sì, ma ...

Devi leggere "Design ed Evolution di C ++" di Stroustrup libro. Avrebbe inibito l'adozione del C ++.

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