Perché le variabili private sono descritte nel file di intestazione accessibile pubblicamente?

11

OK, quindi spero che questa sia una domanda abbastanza soggettiva per i programmatori, ma qui va. Sto allargando continuamente la mia conoscenza delle lingue e delle pratiche di ingegneria del software ... e mi sono imbattuto in qualcosa che non ha assolutamente senso per me.

In C ++, le dichiarazioni di classe includono private: metodi e parametri nel file di intestazione, che, in teoria, è ciò che si passa all'utente per includere se gli si fa una lib.

In Objective-C, @interface s fa praticamente la stessa cosa, costringendo ad elencare i membri privati (almeno, c'è un modo per ottenere metodi privati nel file di implementazione).

Da quello che posso dire, Java e C # consentono di fornire un'interfaccia / protocollo che può dichiarare tutte le proprietà / metodi accessibili pubblicamente e offre al codificatore la possibilità di nascondere i dettagli dell'implementazione tutti nel file di implementazione.

Perché? L'incapsulamento è uno dei principi fondamentali di OOP, perché C ++ e Obj-C non hanno questa capacità di base? Esiste un qualche tipo di best-practice per aggirare Obj-C o C ++ che nasconde l'implementazione all ?

Grazie,

    
posta Stephen Furlani 10.12.2010 - 14:21
fonte

3 risposte

6

La domanda è se il compilatore debba sapere quanto è grande un oggetto. Se è così, allora il compilatore deve conoscere i membri privati per contarli.

In Java, ci sono tipi e oggetti primitivi, e tutti gli oggetti sono allocati separatamente, e le variabili che li contengono sono davvero dei puntatori. Pertanto, poiché un puntatore è un oggetto a dimensione fissa, il compilatore sa quanto grande una cosa rappresenta una variabile, senza conoscere la dimensione effettiva dell'oggetto puntato. Il costruttore si occupa di tutto ciò.

In C ++, è possibile avere oggetti rappresentati localmente o nell'heap. Pertanto, il compilatore deve sapere quanto è grande un oggetto, in modo che possa allocare una variabile o un array locale.

A volte è opportuno dividere la funzionalità di classe in un'interfaccia pubblica e un privato tutto il resto, ed è qui che entra in gioco la tecnica PIMPL (Pointer to IMPLementation). La classe avrà un puntatore a una classe di implementazione privata e alla classe pubblica i metodi possono chiamarlo.

    
risposta data 10.12.2010 - 22:22
fonte
14

A causa della progettazione di C ++, per creare un oggetto nello stack il compilatore deve sapere quanto è grande. Per fare questo ha bisogno di avere tutti i campi presenti nel file di intestazione, in quanto è tutto ciò che il compilatore può vedere quando viene inclusa l'intestazione.

Ad esempio se definisci una classe

class Foo {
    public int a;
    private int b;
};

allora sizeof(Foo) è sizeof(a) + sizeof(b) . Se esisteva un meccanismo per separare i campi privati, l'intestazione potrebbe contenere

class Foo {
    public int a;
};

con sizeof(Foo) = sizeof(a) + ??? .

Se vuoi davvero nascondere i dati privati, prova l'idioma pimpl, con

class FooImpl;
class Foo {
    private FooImpl* impl;
}

nell'intestazione e una definizione per FooImpl solo nel file di implementazione di Foo .

    
risposta data 10.12.2010 - 14:24
fonte
1

Tutto si riduce alla scelta progettuale.

Se vuoi veramente nascondere i dettagli dell'implementazione privata della classe C ++ o Objective-C, allora fornisci una o più interfacce supportate dalla classe (C ++ pure virtual class, Objective-C @protocol) e / o tu rendere la classe in grado di costruire se stessa fornendo un metodo factory statico o un oggetto factory di classe.

Il motivo per cui le variabili private sono esposte nel file di intestazione / dichiarazione di classe / @ interfaccia è che un consumatore della tua classe potrebbe aver bisogno di creare una nuova istanza di esso e un new MyClass() o [[MyClass alloc]init] nel codice cliente ha bisogno del compilatore per capire quanto è grande un oggetto MyClass per fare l'allocazione.

Java e C # hanno anche le loro variabili private dettagliate nella classe - non fanno eccezione a questo, ma IMO il paradigma dell'interfaccia è molto più comune con quelle lingue. Potresti non avere il codice sorgente in ogni caso, ma ci sono abbastanza metadati nel codice compilato / byte per dedurre queste informazioni. Poiché C ++ e Objective-C non hanno questi metadati, l'unica opzione sono i dettagli reali dell'interfaccia classe / @. Nel mondo COM C ++, non esporre le variabili private di alcuna classe ancora in grado di fornire il file di intestazione - perché la classe è pura virtuale. Un oggetto factory class è registrato per creare anche le istanze attuali e ci sono alcuni metadati in varie forme.

In C ++ e Objective-C, è meno lavoro distribuire il file di intestazione rispetto alla scrittura e mantenere un ulteriore file di interfaccia / protocollo @. Questo è uno dei motivi per cui l'implementazione privata viene esposta così spesso.

Un altro motivo in C ++ sono i modelli: il compilatore deve conoscere i dettagli della classe per generare una versione di quella classe specializzata per i parametri forniti. La dimensione dei membri della classe varia in base alla parametrizzazione, quindi è necessario disporre di queste informazioni.

    
risposta data 11.12.2010 - 00:55
fonte

Leggi altre domande sui tag