2011-02-02 13 views
33

Espero alguna aclaración sobre cómo Privado vs Protegido vs Público funciona con respecto a los miembros de la clase cuando se programa en Objective-C - Pensé que sabía la diferencia (He añadido algunos comentarios a mi clase padre Persona con respecto a la misma), pero el hecho de que el compilador no se quejó cuando intenté acceder a un ivar/miembro privado de una clase padre a través de la subclase ahora me tiene confundido.Objective-C - Privado vs Protegido vs Público

Aquí es mi clase principal:

/* 
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 

Aquí está mi clase derivada hombre:

/* 
    Man - Subclass of Person 
    */ 

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

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

    @end 

Y, por último, aquí es principal:

#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; 
     } 

¿No debería el compilador quejarse por qué trato de acceder a aMan.yob arriba? O al usar @property & @synthesize (es decir, los métodos setter y getter), ¿he hecho que ese miembro esté protegido y, por lo tanto, accesible para la subclase?

+2

Nota al margen: si escribe sus ivars en el bloque @ implementation, incluso si @ public y @ protected no son visibles para la subclase. Entonces su suposición es solo correcta para el bloque de interfaz @. – Binarian

Respuesta

17

visibilidad no afecta a los métodos. los métodos son tan buenos como públicos cuando son visibles para los clientes (y posibles peligros/errores cuando son invisibles para los clientes). en cambio, la visibilidad afecta las variables de instancia. intente esto:

#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; 
     } 

esto impide que las subclases de acceder directamente Ivars - obligándolos y los clientes a utilizar los descriptores de acceso (si existe).

esto es un poco débil porque las categorías permiten a los clientes superar esto.

también, los programas objc antiguos de 32 bits realmente no comprobaron que la visibilidad se haya declarado correctamente. afortunadamente, eso ha sido obsoleto en 32 y hay un error en 64.

si realmente desea que algo sea privado para subclases y categorías, use PIMPL con un tipo no publicado/opaco.

visibilidad del método (como se encuentra en Java, C++, etc.) es una característica que usaría en objc.

+0

Justin - Gracias por tu explicación detallada. ¡Tiene sentido ahora! – noobzilla

+0

@noobzilla no hay problema. happy coding – justin

+0

@justin Cuál es la diferencia de visibilidad entre protected y public.I supuse que protected debería permitir el uso exclusivo de subclase y público para todas las clases. Pero cuando lo marqué incluso protegido no presentó ningún error en otras clases y funciona igual que public.NOTE: he agregado mis variables en el archivo .h. – Imran

2

No está accediendo a los miembros; está accediendo a la propiedad en Person que no tiene el nivel de acceso especificado.

+0

Daniel - ¡Gracias! – noobzilla

+0

Cuál es la diferencia de visibilidad entre protegido y público. Supuse que protegido debería permitir el uso exclusivo de subclase y público para todas las clases. Pero cuando lo marqué incluso protegido no presentó ningún error en otras clases y funciona igual que el público .NOTA: he agregado mis variables en el archivo .h. – Imran

3

Está configurando las visibilidades de los ivars, no las propiedades. Sus propiedades generan métodos public getter y setter.

Para realizar propiedades privadas, puede colocar las propiedades en una categoría privada en el archivo .m.

+2

Sería mejor usar una extensión de clase en lugar de una categoría privada. – Chuck

+0

Gracias pwc y Chuck! – noobzilla

24

El truco habitual es crear una extensión de clase dentro del archivo .m y colocar allí su propiedad privada/protegida en lugar de en el encabezado.

//Person.m 

@interface Person() 

@property float height 

@end 

esto oculta la propiedad 'height'

Otro truco es que si quieres crear una propiedad de sólo lectura es declarar en la cabecera como

@property(readonly) int myproperty 

pero en la extensión de clase como readwrite que le permite a su .m modificar el valor usando el getter/setter

@property(readwrite) int myproperty 
+0

Gracias por el consejo Anders! – noobzilla

+0

Gran enlace en extensiones de clase http://www.friday.com/bbum/2009/09/11/class-extensions-explained/ –

Cuestiones relacionadas