Apple Developer Connection
Advanced Search
Member Login Log In | Not a Member? Contact ADC

< 前ページ次ページ >

クラス実装

クラスの定義は、宣言と非常によく似た構造になります。@implementationディレクティブで始まり、@endディレクティブで終わります。

@implementation ClassName :ItsSuperclass
{
    instance variable declarations
}
method definitions
@end

ただし、すべての実装ファイルは、自身のインターフェイスをインポートする必要があります。たとえば、Rectangle.mRectangle.hをインポートします。実装はインポートする宣言を繰り返す必要がないため、次のものは省略しても支障ありません。

これで実装が簡素化されるため、大部分をメソッドの定義に割けます。

#import "ClassName.h"
 
@implementation ClassName
method definitions
@end

クラスのメソッドは、C関数のように1対の中括弧内に定義します。中括弧の前には、インターフェイスファイルの場合と同じ方法でメソッドを宣言しますが、セミコロンは不要です。たとえば、

+ alloc
{
    ...
}
 
- (BOOL)isfilled
{
    ...
}
 
- (void)setFilled:(BOOL)flag
{
    ...
}

可変引数を持つメソッドは、関数と同様に引数を処理します。

#import <stdarg.h>
 
 ...
 
- getGroup:group, ...
{
    va_list ap;
    va_start(ap, group);
    ...
}

このセクションの内容:

インスタンス変数の参照
インスタンス変数の有効範囲


インスタンス変数の参照

デフォルトでは、インスタンスメソッドの定義は、有効範囲内にあるオブジェクトのインスタンス変数をすべて持っています。インスタンスメソッドは、名前だけでインスタンス変数を参照することができます。コンパイラはインスタンス変数を格納するためにCの構造体と同等のものを作成しますが、構造体の詳細は隠されています。オブジェクトのデータを参照するのに、どちらの構造体演算子(.または->)も必要ありません。たとえば、次のメソッド定義はレシーバのfilledインスタンス変数を参照します。

- (void)setFilled:(BOOL)flag
{
    filled = flag;
    ...
}

受信側オブジェクトも、そのfilledインスタンス変数も、このメソッドの引数として宣言していませんが、インスタンス変数は有効範囲内に入っています。このようなメソッド構文の簡素化によって、Objective-Cコードの記述は非常に簡潔で分かり易くなっています。

インスタンス変数がレシーバでないオブジェクトに属する場合は、オブジェクトの型を静的な型定義によってコンパイラに明示しなければなりません。静的に型定義したオブジェクトのインスタンス変数を参照するには、構造体ポインタ演算子(->)を使用します。

たとえば、Siblingクラスで静的に型定義したオブジェクトtwinをインスタンス変数として宣言するとします。

@interface Sibling :NSObject
{
    Sibling *twin;
    int gender;
    struct features *appearance;
}

静的に型定義したオブジェクトのインスタンス変数がクラスの有効範囲内にあれば(twinが同じクラスに型定義されているため、この例ではインスタンス変数が有効範囲内にあります)、Siblingメソッドはインスタンス変数を直接設定することができます。

- makeIdenticalTwin
{
    if ( !twin ) {
        twin = [[Sibling alloc] init];
        twin->gender = gender;
        twin->appearance = appearance;
    }
    return twin;
}

インスタンス変数の有効範囲

インスタンス変数はクラスインターフェイスで宣言しますが、それらはクラスを使用する方法ではなく、クラスを実装する方法が重要な問題となります。オブジェクトのインターフェイスは、内部データ構造ではなく、そのメソッドを基盤にします。

多くの場合、メソッドとインスタンス変数は、次の例に示すように1対1で対応しています。

- (BOOL)isFilled
{
    return filled;
}

しかし、必ずしもそうである必要はありません。インスタンス変数に格納されていない情報を返すメソッドもありますし、オブジェクトが公開しない情報を格納するインスタンス変数もあります。

クラスにその時々で変更を加えていくとき、クラスで宣言するメソッドは同じままでも、使用するインスタンス変数は変わる可能性があります。メッセージがクラスのインスタンスと対話するための伝達手段であるかぎり、このような変化は実際にはインターフェイスに影響しません。

データを隠すオブジェクトの能力を適用するために、コンパイラはインスタンス変数の有効範囲を制限しています。つまり、プログラム内でのインスタンス変数の可視性を制限しています。しかし、柔軟性を提供するために、有効範囲を3段階で明示的に設定することもできます。各段階はコンパイラディレクティブで指定します。

ディレクティブ

意味

@private

インスタンス変数を宣言するクラス内でのみ当該変数にアクセス可能。

@protected

インスタンス変数を宣言するクラス内および継承するクラス内で当該変数にアクセス可能。

@public

対象インスタンス変数にどこからでもアクセス可能。

@package

64ビットでは@packageインスタンス変数は、クラスを実装するイメージ内では@publicのように振舞いますが、クラスを実装するイメージの外側では@privateのように振舞います。

これは変数と関数のprivate_externに似ています。クラス実装のイメージの外側のコードからインスタンス変数を使用しようとすると、すべてリンクエラーとなります。これはフレームワーククラス内のインスタンス変数に最も役立ちます。フレームワーククラスでは@privateは制限が多すぎるかもしれませんが、@protected@publicは寛容すぎます。

これを図 2-1に図示します。


図 2-1  インスタンス変数の有効範囲

インスタンス変数の有効範囲

ディレクティブは、それ以降、次のディレクティブまたはリストの終わりまでの間に記述されたインスタンス変数に適用されます。次の例では、ageおよびevaluationインスタンス変数は@private、namejob、およびwageは@protected、bossは@publicです。

@interface Worker :NSObject
{
    char *name;
@private
    int age;
    char *evaluation;
@protected
    id job;
    float wage;
@public
    id boss;
}

デフォルトでは、無指定のインスタンス変数(上記のnameなど)はすべて@protectedです。

クラスで宣言するインスタンス変数はすべて、どのような指定をされていても、クラス定義の有効範囲内にあります。たとえば、上記のWorkerクラスのように、jobインスタンス変数を宣言するクラスは、メソッド定義で当該変数を参照することができます。

- promoteTo:newPosition
{
    id old = job;
    job = newPosition;
    return old;
}

言うまでもなく、クラスが自身のインスタンス変数にアクセスできなければ、インスタンス変数は意味がありません。

本来なら、クラスは継承するインスタンス変数にもアクセスできます。インスタンス変数を参照する能力は、通常、変数とともに継承されます。クラスがデータ構造全体をその有効範囲内に保つことは、クラス定義を継承元のクラスを詳細化するものと考えている場合には特に意味があります。上記のpromoteTo:メソッドは、Workerクラスからjobインスタンス変数を継承するクラスであれば同様に定義することができます。

しかし、継承先のクラスによるインスタンス変数への直接アクセスを制限するべき場合があるそれなりの理由があります。

インスタンス変数の有効範囲を、当該変数を宣言するクラスに限定するには、そのインスタンス変数を@privateとして指定する必要があります。@privateとして指定されたインスタンス変数は、パブリックアクセサメソッドが存在する場合に、それらを呼び出すことによってのみサブクラスから利用できます。

逆に、変数を@publicとして指定すると、その変数を継承したり宣言したりするクラス定義の外でも広く利用可能になります。通常、他のオブジェクトがインスタンス変数内の情報を取得するには、情報を要求するメッセージを送信する必要があります。しかし、パブリックインスタンス変数は、C構造体のフィールドであるかのように、どこからでもアクセスすることができます。たとえば、

Worker *ceo = [[Worker alloc] init];
ceo->boss = nil;

オブジェクトは静的に型定義する必要があることに注意してください。

インスタンス変数を@publicとして指定すると、オブジェクトによる当該データの隠蔽が無効になります。これは、表示や不用意な間違いからデータを保護するためオブジェクト内にカプセル化するという、オブジェクト指向プログラミングの原則に反します。したがって、特別な場合を除いて、パブリックインスタンス変数の使用は避けるべきです。



< 前ページ次ページ >


Last updated: 2007-10-31




Did this document help you?
Yes: Tell us what works for you.

It’s good, but: Report typos, inaccuracies, and so forth.

It wasn’t helpful: Tell us what would have helped.
Get information on Apple products.
Visit the Apple Store online or at retail locations.
1-800-MY-APPLE

Copyright © 2007 Apple Inc.
All rights reserved. | Terms of use | Privacy Notice