开发者

Objective-C - Private vs Protected vs Public

开发者 https://www.devze.com 2023-02-08 04:46 出处:网络
I am hoping for some clarification on how Private vs Protected vs Public works with respect to class members when programming in Objective-C - I thought I knew the difference (I\'ve added some comment

I am hoping for some clarification on how Private vs Protected vs Public works with respect to class members when programming in Objective-C - I thought I knew the difference (I've added some comments to my parent class Person with respect to the same), but the fact that the compiler did not complain when I tried to access a private ivar/member of a parent class via the subclass now has me confused.

Here is my Parent Class:

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

Here is my derived class Man:

    /*
     Man - Subclass of Person
    */

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

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

    @end

And finally, here is main:

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

Shouldn't the compiler complain why I try to access aMan.yob above? Or by using @property & @synthesize (i.e. the setter and getter methods) have I essentially made that member protected and therefore accessible to the subclass?


The usual trick is to create a class extension inside the .m file and put your private/protected property there instead of in the header.

//Person.m

@interface Person()

@property float height

@end

this hides the 'height' property

Another trick is if you want to create a readonly property is to declare it in the header as

@property(readonly) int myproperty

but in the class extension as readwrite which allows your .m to modify the value using the getter/setter

@property(readwrite) int myproperty


visibility does not affect methods. methods are as good as public when visible to clients (and potential pitfalls/bugs when invisible to clients). instead, visibility affects instance variables. try this:

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

this prevents the subclasses from accessing ivars directly -- forcing them and clients to use the accessors (if provided).

this is all a bit weak because categories allow clients to overcome this.

also, older 32 bit objc programs did't really check that the visibility was declared correctly. fortunately, that's been deprecated in 32 and an error in 64.

if you really want something to be private to subclasses and categories, use PIMPL with an unpublished/opaque type.

method visibility (as found in Java, C++, etc.) is a feature i'd use in objc.


You are setting the visibilities of the ivars, not the properties. Your properties generate public getter and setter methods.

To make private properties, you can put the properties in a private category in the .m file.


You aren't accessing the members - you are accessing the property on Person which does not have the access level specified.

0

精彩评论

暂无评论...
验证码 换一张
取 消