Le direttive @public, @protected e @private sono non vincolante obiettivo-C, sono compilatore suggerimenti in merito l'accessibilità delle variabili. NON VI LIMITA a impedirne l'accesso.
esempio:
@interface Example : Object
{
@public
int x;
@private
int y;
}
...
...
id ex = [[Example alloc ] init];
ex->x = 10;
ex->y = -10;
printf(" x = %d , y = %d \n", ex->x , ex->y);
...
Il compilatore gcc sputa:
main.m: 56: 1: avviso: istanza variabile ‘y’ è @private; questo sarà un errore grave in futuro
Main.m: 57: 1: warning: la variabile di istanza 'y' è @private; questo sarà un errore hardware in futuro
una volta per ogni accesso "innapropriate" per membro y "privato", ma compila comunque.
Quando viene eseguito si ottiene
x = 10 , y = -10
Così è davvero a te non scrivere codice di accesso in questo modo, ma perché objc è un superset di C, sintassi C funziona bene, e tutti le classi sono trasparenti.
È possibile impostare il compilatore per trattare questi avvisi come errori e cauzione, ma l'obiettivo C non è impostato internamente per questo tipo di rigore. Il dispatch del metodo dinamico dovrebbe verificare la portata e l'autorizzazione per ogni chiamata (slooooowwwww ...), quindi al di là di un avviso in fase di compilazione, il sistema si aspetta che il programmatore rispetti l'ambito dei membri dei dati.
Ci sono diversi trucchi per ottenere la privacy dei membri in oggettivo-C. Uno è quello di assicurarsi di inserire l'interfaccia e le implementazioni della classe in file separati .h e .m, rispettivamente, e di mettere i membri dei dati nel file di implementazione (il file .m). Quindi i file che importano le intestazioni non hanno accesso ai membri dati, solo la classe stessa. Quindi fornire i metodi di accesso (o non) nell'intestazione. È possibile implementare le funzioni setter/getter nel file di implementazione per scopi diagnostici se si desidera e saranno richiamabili, ma l'accesso diretto ai dati non sarà possibile.
esempio:
@implementation Example2 :Object
{
//nothing here
}
double hidden_d; // hey now this isn't seen by other files.
id classdata; // neither is this.
-(id) classdata { return [classdata data]; } // public accessor
-(void) method2 { ... }
@end
// this is an "informal category" with no @interface section
// these methods are not "published" in the header but are valid for the class
@implementation Example2 (private)
-(void)set_hidden_d:(double)d { hidden_d = d; }
// You can only return by reference, not value, and the runtime sees (id) outside this file.
// You must cast to (double*) and de-reference it to use it outside of this file.
-(id) hidden_d_ptr { return &hidden_d;}
@end
...
[Main.m]
...
ex2 = [[Example2 alloc] init];
double d = ex2->hidden_d; // error: 'struct Example2’ has no member named ‘hidden_d’
id data = ex2->classdata; // error: 'struct Example2’ has no member named ‘classdata’
id data = [ex2 classdata] // OK
[ex2 set_hidden_d : 6.28318 ]; // warning:'Example2' may not respond to '-set_hidden_d:'
double* dp = [ex2 hidden_d_ptr]; // (SO UGLY) warning: initialization from incompatible pointer type
// use (double*)cast -- <pointer-to-pointer conversion>
double d = (*dp); // dereference pointer (also UGLY).
...
Il compilatore emetterà avvisi per tali imbrogli palesi, ma andrà avanti e fiducia che si sa cosa si sta facendo, e che hai le tue ragioni (do (davvero?) tu?). Sembra un sacco di lavoro? Incline a errori? Yay Baby! Prova a riconsiderare il tuo codice prima di ricorrere ai trucchi magici e alla polpetta come questo.
Ma eccolo. In bocca al lupo.
In particolare, il compilatore in questione sembra essere Clang> 2. (Esistente) GCC non lo farà. –
In questo contesto, 'Clang' è uguale a 'LLVM', giusto? –
@ranReloaded - no. Vi sono gcc - gcc front e backend, gcc-llvm - gcc frontend, llvm backend - e clang - clang frontend, llvm backend. Ho provato solo su clang, Josh è stato testato su uno dei gcc's. YMMV, provalo con qualunque compilatore stai usando e vedi. – CRD