Подтвердить что ты не робот

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), я по существу сделал этот элемент защищенным и, следовательно, доступным для подкласса?

4b9b3361

Ответ 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, который не имеет указанного уровня доступа.