Perché dobbiamo inserire i membri privati ​​nelle intestazioni?


62

Le variabili private sono un modo per nascondere la complessità e i dettagli di implementazione all'utente di una classe. Questa è una caratteristica piuttosto interessante. Ma non capisco perché in c ++ dobbiamo metterli nell'intestazione di una classe. Vedo due inconvenienti fastidiosi di questo:

  • Raggruppa l'intestazione dall'utente
  • Forza la ricompilazione di tutte le librerie client ogni volta che gli interni vengono modificati

C'è una ragione concettuale dietro questo requisito? È solo per facilitare il lavoro fuori dal compilatore?


puoi dichiarare una struttura vuota nell'intestazione ma poi puoi usare i puntatori a tale struttura solo quando la usi (e non puoi assegnarne una)
maniaco del cricchetto

3
@ratchetfreak: No, empty ( struct foo{};) non è consentito, ma le dichiarazioni forward ( struct foo;) lo sono.
MSalters,

@MSalters è quello che volevo dire
maniaco del cricchetto,

1
Consentitemi di aggiungere un aspetto negativo: * Scrivere le intestazioni delle funzioni private nel file .h è un'enorme perdita di tempo. (dimenticando le lezioni di amici per un momento)
Jonny,

Risposte:


68

È perché il compilatore C ++ deve conoscere la dimensione effettiva della classe per allocare la giusta quantità di memoria all'istanza. E la dimensione include tutti i membri, anche quelli privati.

Un modo per evitarlo è usare l' idioma di Pimpl , spiegato da Herb Sutter nelle sue serie # 24 e # 28 del Guru della settimana .

Aggiornare

In effetti, questo (o più in generale, la / le distinzione / i del file di intestazione / sorgente #include) è un grave ostacolo in C ++, ereditato da C. Ai tempi in cui è stato creato C ++ C, non c'era ancora esperienza con lo sviluppo di software su larga scala, dove questo inizia a causare problemi reali. Le lezioni apprese da allora sono state seguite dai progettisti di linguaggi più recenti, ma il C ++ è vincolato da requisiti di compatibilità con le versioni precedenti, il che rende davvero difficile affrontare un problema così fondamentale nella lingua.


Questo tipo di informazioni non è contenuto solo nella libreria di classi? Viene utilizzato per il collegamento?
Simon Bergot,

@Simon, cosa intendi con "biblioteca di classe"?
Péter Török,

Intendo la raccolta di file oggetto contenenti la definizione della classe e i metodi
Simon Bergot,

7
Quando è stato creato il C ++, AT & T / Bell Labs (il datore di lavoro di Stroustrups all'epoca) aveva certamente esperienza nello sviluppo di C su larga scala. Il loro software di commutazione del telefono 5ESS era all'epoca probabilmente il più grande programma C singolo al mondo. Le idee iniziali su OO sono già visibili in quella base di codice e Cfront ha imitato quelle tecniche. Tuttavia, la nozione di privateè più moderna.
MSalters,

1
In C, avresti semplicemente messo l'allocatore in una funzione di libreria; il cliente non sarebbe in grado di allocare una tale struttura. Questo aumenta un po 'il sovraccarico, ma rende la migrazione del codice tra le versioni banale, quindi spesso vale la pena. Tuttavia, tende a condurre a uno stile di codice molto distinto da quello visto con C ++.
Donal Fellows,

15

La definizione della classe deve essere sufficiente affinché il compilatore produca un layout identico in memoria ovunque sia stato utilizzato un oggetto della classe. Ad esempio, dato qualcosa come:

class X { 
    int a;
public:
    int b;
};

Il compilatore avrà in genere aall'offset 0 e ball'offset 4. Se il compilatore lo vedesse come solo:

class X { 
public:
    int b;
};

Vorrebbe "pensare" che bdovrebbe essere all'offset 0 anziché all'offset 4. Quando il codice che utilizza quella definizione assegnata a b, il codice che usa la prima definizione vedrebbe aessere modificato, e viceversa.

Il solito modo per ridurre al minimo gli effetti delle modifiche apportate alle parti private della classe è di solito chiamato idioma del brufolo (di cui sono sicuro che Google può fornire una grande quantità di informazioni).


1
Sto chiedendo una decisione di progettazione. Ovviamente dovresti mettere la dichiarazione del membro privato da qualche parte affinché la lingua funzioni. Ma perché dovrebbe essere nell'intestazione e non in un posto più privato?
Simon Bergot,

7
@Simon: L'intestazione è tutto ciò che il compilatore vede per dirgli che aspetto ha la classe / struttura. Ci sono state discussioni sull'aggiunta di qualcosa come i moduli al C ++, che nasconderebbe quel tipo di dati un po 'di più, ma finora non è stato approvato (anche se non è stato completamente eliminato).
Jerry Coffin,

3
Tuttavia, una banale regola sarebbe quella di allocare tali membri privati ​​".cpp-definiti" per ultimi. Ciò significa che gli offset dei membri pubblici e "normali" non dipenderebbero da loro. IMO il vero motivo è che non puoi ereditare da una tale classe, poiché la parte derivata deve seguire anche quei membri privati.
MSalters,

3

Ci sono probabilmente molte ragioni. Sebbene la maggior parte delle altre classi non possano accedere ai membri privati, possono comunque accedere alle classi degli amici. Quindi almeno in questo caso potrebbero essere necessari nell'intestazione, quindi la classe di amici può vedere che esistono.

La ricompilazione di file dipendenti può dipendere dalla struttura di inclusione. Includere i file .h in un file .cpp anziché in un'altra intestazione può in alcuni casi impedire lunghe catene di ricompilazioni.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.