2011-02-02 18 views
33

Spero di avere qualche chiarimento su come Private vs Protected vs Public funziona rispetto ai membri della classe durante la programmazione in Objective-C - Pensavo di conoscere la differenza (ho aggiunto alcuni commenti alla mia classe genitore Person rispetto allo stesso), ma il fatto che il compilatore non si sia lamentato quando ho provato ad accedere ad un ivar/membro privato di una classe genitore tramite la sottoclasse ora mi ha confuso.Objective-C - Privato vs Protetto contro Pubblico

Qui è la mia classe genitore:

/* 
Person.h 
*/ 

#import <Foundation/Foundation.h> 

@interface Person : NSObject 
{ 
    //We can also define class members/iVars that are of type private 
    //This means they can only be accessed by the member functions 
    //of the class defining them and not subclasses 
    @private 
    int yob;  

    //We can also define class members/iVars that are of type public 
    //Public members can be accessed directly 
    @public 
    bool alive; 

    //By default class members/iVars are of type protected 
    //This means they can only be accessed by a class's own 
    //member functions and subclasses of the class and typically 
    //also by friend functions of the class and the subclass 
    //We can explicitly define members to be protected using the 
    //@protected keyword 

    @protected 
    int age; 
    float height; 

} 
@property int age; 
@property float height; 
@property int yob; 
@property bool alive; 

@end 

Qui è la mia classe derivata Man:

/* 
    Man - Subclass of Person 
    */ 

    #import <Foundation/Foundation.h> 
    #import "Person.h" 

    @interface Man : Person 
    { 
     //iVar for Man 
     float mWeight; 
    } 
    @property float mWeight; 

    @end 

E, infine, ecco la principale:

#import <Foundation/Foundation.h> 
#import "Person.h" 
#import "Man.h" 

    int main (int argc, const char * argv[]) 
     { 
      NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 

      //Create a Person object 
      Person * aPerson = [[Person alloc]init]; 

      //Create a Man object 
      Man * aMan = [[Man alloc]init]; 

      //Let's attempt to modify our Person class members 
      aPerson.height = 5.11; //Protected 
      aPerson.age = 21; //Protected 
      aPerson.yob = 2010; //Private 
      aPerson.alive = YES; //Public 

      //Let's now attempt to modify the same members via our 
      //derived class Man - in theory, the private members should 
      //not be accessible by the derived class man 
      aMan.height = 6; //Protected 
      aMan.age = 26; //Protected 
      aMan.yob = 2011; //Private 
      aMan.alive = YES; //Public 
      aMan.mWeight = 190; //Protected member of Man Class 

      [pool drain]; 
      return 0; 
     } 

Il compilatore non dovrebbe lamentarsi del motivo per cui provo ad accedere a a.yob sopra? O usando @property & @synthesize (vale a dire i metodi setter e getter) ho essenzialmente reso quel membro protetto e quindi accessibile alla sottoclasse?

+2

Nota a margine: se scrivi i tuoi ivar nel blocco @ implementation, anche @ public e @ protected non sono visibili dalla sottoclasse. Quindi la tua ipotesi è corretta solo per il blocco di interfaccia @. – Binarian

risposta

17

visibilità non influenza i metodi. i metodi sono buoni come pubblici quando sono visibili ai clienti (e potenziali insidie ​​/ bug quando sono invisibili ai client). la visibilità, invece, influenza le variabili di istanza. provare questo:

#import <Foundation/Foundation.h> 
#import "Person.h" 
#import "Man.h" 


    int main (int argc, const char * argv[]) 
     { 
      NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 

      //Create a Person object 
      Person * aPerson = [[Person alloc]init]; 

      //Create a Man object 
      Man * aMan = [[Man alloc]init]; 


      //Let's attempt to modify our Person class members 
      aPerson->height = 5.11; //Protected 
      aPerson->age = 21; //Protected 
      aPerson->yob = 2010; //Private 
      aPerson->alive = YES; //Public 


      //Let's now attempt to modify the same members via our 
      //derived class Man - in theory, the private members should 
      //not be accessible by the derived class man 
      aMan->height = 6; //Protected 
      aMan->age = 26; //Protected 
      aMan->yob = 2011; //Private 
      aMan->alive = YES; //Public 
      aMan->mWeight = 190; //Protected member of Man Class 



      [pool drain]; 
      return 0; 
     } 

questo impedisce le sottoclassi di accedere direttamente Ivars - costringendoli e clienti di utilizzare le funzioni di accesso (se previsto).

questo è tutto un po 'debole perché le categorie consentono ai clienti di superare questo.

Inoltre, i vecchi programmi objc a 32 bit non controllavano realmente che la visibilità fosse dichiarata correttamente. fortunatamente, questo è stato deprecato in 32 e un errore in 64.

se vuoi davvero qualcosa da privato per sottoclassi e categorie, usa PIMPL con un tipo non pubblicato/opaco.

la visibilità del metodo (come trovata in Java, C++, ecc.) È una funzionalità che utilizzerei in objc.

+0

Justin - Grazie per la tua spiegazione dettagliata. Ha senso ora! – noobzilla

+0

@noobzilla nessun problema. happy coding – justin

+0

@justin Qual è la differenza di visibilità tra protetto e pubblico. Supponevo che protetto potesse essere usato solo per sottoclassi e pubblico per tutte le classi. Ma quando ho controllato anche protetto non poneva alcun errore in altre classi e funziona come public.NOTA: ho aggiunto le mie variabili nel file .h. – Imran

2

Non si accede ai membri: si accede alla proprietà su Person a cui non è specificato il livello di accesso.

+0

Daniel - Grazie! – noobzilla

+0

Qual è la differenza di visibilità tra protetto e pubblico. Supponevo che protetto potesse essere utilizzato solo per sottoclassi e pubblico per tutte le classi. Ma quando ho controllato anche protetto non poneva alcun errore in altre classi e funziona come pubblico . NOTA: ho aggiunto le mie variabili nel file .h. – Imran

3

Si sta impostando la visibilità degli ivar, non le proprietà. Le tue proprietà generano metodi pubblici getter e setter.

Per rendere proprietà private, è possibile inserire le proprietà in una categoria privata nel file .m.

+2

Sarebbe meglio usare un'estensione di classe piuttosto che una categoria privata. – Chuck

+0

Grazie pwc e Chuck! – noobzilla

24

Il solito trucco consiste nel creare un'estensione di classe all'interno del file .m e inserire la proprietà privata/protetta lì invece che nell'intestazione.

//Person.m 

@interface Person() 

@property float height 

@end 

questo nasconde la proprietà 'height'

Un altro trucco è che se si vuole creare una proprietà di sola lettura è di dichiararla nell'intestazione come

@property(readonly) int myproperty 

ma nell'estensione della classe come readwrite che consente al tuo .m di modificare il valore utilizzando il getter/setter

@property(readwrite) int myproperty 
+0

Grazie per il suggerimento Anders! – noobzilla

+0

Ottimo link sulle estensioni di classe http://www.friday.com/bbum/2009/09/11/class-extensions-explained/ –

Problemi correlati