Objective-C @public,@private,@protected,有効範囲 【初級編 第9回】

この記事は2012年10月21日に書かれたものです。内容が古い可能性がありますのでご注意ください。


Objective-C @public,@private,@protected,有効範囲 【初級編 第9回】

前回継承に関して述べました。継承した場合、スーパークラスのインスタンス変数が使用できるといいましたが
どんな場合でも使用できるわけではありません。というのもインスタンス変数には有効な範囲があり、
Objective-Cでは以下のように区分できます。

  • どこからでもアクセスできるインスタンス変数
  • クラス内からしかアクセスできないインスタンス変数
  • クラス内及びそのクラスを継承しているクラス(直接でなくてもいい)からアクセスできるインスタンス変数

今までのコードでは出てきていませんでしたが、それぞれの有効範囲を示すためのディレクティブが用意されています。
ディレクティブとは第2回でも出てきましたが、プリプロセッサに対して指示を出すための命令となります。
今まで登場したものでは「@interface」「@end」などがありましたね。
ここで新たに登場するインスタンス変数の有効範囲を示すのが「@public」「@private」「@protected」となります。
それを確認するためにコードを書き直してみます。

まずはどこからでもアクセスできるインスタンス変数を指定する「@public」から見てみます。
インスタンス変数に指定をするには以下のように行います。
Person.mを書き換えます。

Person.m

#import <objc/Object.h>

@interface Person:Object
{
        //属性を表す
        @public
        double height;
        double weight;
}

//アクセサ
-(double)height;
-(void)setHeight:(double)personHeight;
-(double)weight;
-(void)setWeight:(double)personWeight;
-(id)initWithWeight:(double)personWeigth height:(double)personHeight;
@end

main.m

#import <objc/Object.h>
#import "Bmi.h"
#import "Person.h"

int main(void){
    Person *mine = [[Person alloc] initWithWeight:65.0 height:1.72];
    printf("%2.1fn",[Bmi calcBmi:[mine weight] height:[mine height]]);
    printf("%2.1fn",[Bmi calcProperWeight:mine->height]);
    [mine free];
    return 0;
}

まずヘッダーファイル「Person.h」から見てみましょう。
インスタンス変数の前に「@public」がついていますね。これで「height」「weight」はどこからもアクセスできるように
なっています。

次に「main.m」を見てみましょう。
6行目を見てください。今まではインスタンス化されたどのクラスのオブジェクトでも表すことのできるid型を
使用していましたが、今回はPerson型を使用しています。
クラスとして定義したものは型として使用できるようになるのでこのような使い方ができます。
このときデータ型とは違い、ポインタ型の変数としなければならないため「*」がつきます。

オブジェクトの持つ高さの属性にアクセスするためにアクセサを使用したメッセージ送信の方法と
少し異なる呼び出し方法の両方を使用しています。7行目は今までと同じでアクセサを介して値を取得していますが、
8行目では身長を取得する際に「オブジェクト->インスタンス変数」というやり方を使用しています。
Objective-Cではオブジェクト内のインスタンス変数にアクセスするときにはこういった呼び出し方もできるのですが、
id型とした場合はできませんので、注意してください。
また、このようなクラスの外からクラス内のインスタンス変数を直接呼び出すことができるのは、
「@public」となっているからです。
そこで試しに「@public」を外してみましょう。以下のような警告がでるはずです。


上のスクリーンショットを見て気づかれる方もいるかもしれませんが、有効範囲の指定をしないと「@protected」扱いとなります。
この「@protected」がクラス内及びそのクラスを継承しているクラス(直接でなくてもいい)からアクセスできるインスタンス変数を表します。

最後に残りのクラス内からしかアクセスできないインスタンス変数を指定する「@private」を見てみましょう。
1つ新しいクラスを作ります、ということで従業員でも作成しましょう。
従業員は基本的には人(Person)であるため、Personクラスを継承します。検証のために「Person.m」のインスタンス変数を
「@private」にします。

Employee.hファイル

@interface Employee:Person{
   int uid;
}
-(void)initWithWeight:(double)empWeight height:(double)empHeight uid:(int)empId;
@end

Employee.m

#import "Employee.h"

@implementation Employee

-(void)initWithWeight:(double)empWeight height:(double)empHeight uid:(int)empId{
    weight = empWeight;
    height = empHeight;
    uid = empId;
}
@end

実行すると以下のようになります。

インスタンス変数「weight」と「height」はクラス内からしかアクセスできなくなっているため、Personクラスを継承した
Employeeクラスであってもアクセスができません。そのためアクセサメソッドを介してアクセスすることになります。
Employee.mで以下のようにやれば問題ありません。
[super setWeight:empWeight];
[super setHeight:empHeight];

今回のまとめとしては

  • インスタンス変数には有効範囲がある
  • 「@public」ディレクティブを指定するとどこからでもアクセスできるインスタンス変数となる
  • 「@protected」ディレクティブを指定するとクラス内及びそのクラスを継承しているクラス(直接でなくてもいい)から
    アクセスできるインスタンス変数となる
  • 「@private」ディレクティブを指定するとクラス内からしかアクセスできないインスタンス変数となる
  • クラスを型として使用することができるが、「*」をつけてポインタ型の変数とする

といったところでしょうか。

  • このエントリーをはてなブックマークに追加

コメント

  1. この記事へのコメントはありません。

  1. この記事へのトラックバックはありません。

PAGE TOP