Objective-C - Частный и защищенный против Public
Я надеюсь на некоторое разъяснение того, как Private vs Protected vs Public работает в отношении членов класса при программировании в Objective-C - я думал, что знаю разницу (я добавил некоторые комментарии к моему родительскому классу Person в отношении то же самое), но тот факт, что компилятор не жаловался, когда я пытался получить доступ к частному ivar/члену родительского класса через подкласс, теперь меня смутил.
Вот мой родительский класс:
/*
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 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 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 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), я по существу сделал этот элемент защищенным и, следовательно, доступным для подкласса?
Ответы
Ответ 1
видимость не влияет на методы. методы так же хороши, как и публичные, когда они видны клиентам (и потенциальные ловушки/ошибки, когда они невидимы для клиентов). вместо этого видимость влияет на переменные экземпляра. попробуйте следующее:
#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 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 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;
}
это препятствует доступу подклассов напрямую к ivars - принуждение их и клиентов к использованию аксессуаров (если предусмотрено).
все это немного слабо, потому что категории позволяют клиентам преодолеть это.
более старые 32-битные программы objc действительно проверяли, что видимость была объявлена правильно. к счастью, это было устаревшим в 32 и ошибкой в 64.
если вы действительно хотите, чтобы что-то было частным для подклассов и категорий, используйте PIMPL с неопубликованным/непрозрачным типом.
видимость метода (как показано на Java, С++ и т.д.) - это функция, которую я бы использовал в objc.
Ответ 2
Обычный трюк состоит в том, чтобы создать расширение класса внутри файла .m и поместить ваше личное/защищенное свойство там, а не в заголовок.
//Person.m
@interface Person()
@property float height
@end
это скрывает свойство 'height'
Другим трюком является то, что вы хотите создать свойство readonly, чтобы объявить его в заголовке
как
@property(readonly) int myproperty
но в расширении класса как readwrite, который позволяет вашему .m изменять значение с помощью getter/setter
@property(readwrite) int myproperty
Ответ 3
Вы устанавливаете видимость иваров, а не свойств. Ваши свойства генерируют общедоступные методы getter и setter.
Чтобы сделать частные свойства, вы можете поместить свойства в приватную категорию в файл .m.
Ответ 4
Вы не получаете доступ к членам - вы получаете доступ к свойству на Person
, который не имеет указанного уровня доступа.