2011-02-02 2 views
33

Я надеюсь на некоторое разъяснение того, как Private vs Protected vs Public работает с членами класса при программировании в Objective-C - я думал, что знаю разницу (я добавил некоторые комментарии к моему родительскому классу Person по отношению к тому же), но тот факт, что компилятор не жаловался, когда я пытался получить доступ к частному ivar/члену родительского класса через подкласс, теперь меня смущает.Objective-C - Private vs Protected vs Public

Вот мой родительский класс:

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

Вот мой производный класс Man:

/* 
    Man - Subclass of Person 
    */ 

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

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

    @end 

И, наконец, вот основные:

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

Не должен компилятор жаловаться, почему я пытаюсь получить доступ к aMan.yob выше? Или, используя @property & @synthesize (т. Е. Метод setter и getter), я по существу сделал этот элемент защищенным и, следовательно, доступным для подкласса?

+2

Замечание: если вы пишете ваши ivars в блоке реализации @, то даже @ public и @ protected не отображаются подклассом. Поэтому ваше предположение верно только для блока интерфейса @. – Binarian

ответ

17

видимость не влияет на методы. методы так же хороши, как и публичные, когда они видны клиентам (и потенциальные ловушки/ошибки, когда они невидимы для клиентов). вместо этого видимость влияет на переменные экземпляра. попробуйте это:

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

это предотвращает подклассы доступа Ивара напрямую - заставляя их и клиент использовать аксессор (если это предусмотрено).

все это немного слабо, потому что категории позволяют клиентам преодолеть это.

также, старые 32-разрядные программы objc действительно не проверяли правильность видимости. к счастью, это было устаревшим в 32 и ошибкой в ​​64.

Если вы действительно хотите, чтобы что-то было частным для подклассов и категорий, используйте PIMPL с неопубликованным/непрозрачным типом.

видимость метода (как в Java, C++ и т. Д.) - это функция, которую я бы использовал в objc.

+0

Justin - Спасибо за подробное объяснение. Теперь имеет смысл! – noobzilla

+0

@noobzilla проблем нет. счастливое кодирование – justin

+0

@justin Какая разница видимости между защищенными и public.I предположил, что защищенный должен позволять использоваться только для подкласса и общедоступным для всех классов. Но когда я проверил, даже защищенный, не представлял никакой ошибки в других классах и работайте так же, как public.NOTE-Я добавил свои переменные в файл .h. – Imran

2

Вы не видите список участников - вы делаете доступ к собственности на Person, у которого нет указанного уровня доступа.

+0

Daniel - Спасибо! – noobzilla

+0

Какая разница видимости между защищенными и public.I предположил, что защищенный должен позволять использовать только для подкласса и для всех классов. Но когда я проверил даже защищенный, он не представлял никаких ошибок в других классах и не работал так же, как public .NOTE-Я добавил свои переменные в файл .h. – Imran

3

Вы устанавливаете видимости иваров, а не свойства. Ваши свойства генерируют общедоступные методы getter и setter.

Чтобы сделать частную собственность, вы можете поместить свойства в личную категорию в .m-файл.

+2

Лучше использовать расширение класса, а не частную категорию. – Chuck

+0

Спасибо, pwc и Чак! – noobzilla

24

Обычный трюк состоит в том, чтобы создать расширение класса внутри файла .m и поместить ваше личное/защищенное свойство там, а не в заголовок.

//Person.m 

@interface Person() 

@property float height 

@end 

это скрывает свойство «высота»

Другой трюк: если вы хотите создать только для чтения свойство является объявить его в заголовке в

@property(readonly) int myproperty 

но в расширении класса как readwrite, который позволяет вашему .m изменять значение с использованием геттера/сеттера

@property(readwrite) int myproperty 
+0

Спасибо за отзыв Anders! – noobzilla

+0

Отличная ссылка на расширения классов http://www.friday.com/bbum/2009/09/11/class-extensions-explained/ –

Смежные вопросы