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

< 前ページ次ページ >

静的な型定義

オブジェクト宣言においてidの代わりに、クラス名のポインタを使用する場合は、次のようになります。

Rectangle *thisObject;

コンパイラは、宣言した変数の値を、宣言で指定されたクラスのインスタンス、または指定されたクラスを継承するクラスのインスタンスのいずれかに限定します。上記の例では、thisObjectは何らかのRectangleに限定されます。

静的に型定義したオブジェクトは、idとして宣言されたオブジェクトと同じ内部データ構造を持ちます。型はオブジェクトには影響しません。コンパイラに提供するオブジェクトに関する情報の量と、ソースコードを読む他の人が得られる情報の量にのみ影響します。

静的な型定義は、実行時のオブジェクトの処理方法にも影響しません。静的に型定義したオブジェクトは、id型のインスタンスを作成するのと同じクラスメソッドによって動的に割り当てられます。SquareがRectangleのサブクラスの場合、次のコードはRectangleのインスタンス変数だけでなく、Squareのインスタンス変数をすべて持ったオブジェクトを生成します。

Rectangle *thisObject = [[Square alloc] init];

静的に型定義したオブジェクトに送信するメッセージは、idとして型定義したオブジェクトと同じように、動的にバインドされます。さらに、静的に型定義したレシーバの実際の型は、実行時にメッセージング処理の一環として決定されます。次の例は、thisObjectに送信されるdisplayメッセージです。

[thisObject display];

これはRectangleスーパークラスのメソッドではなく、Squareクラスに定義されているメソッドのバージョンを実行します。

オブジェクトに関する詳細な情報をコンパイラに提供することで、静的な型定義にはidとして型定義したオブジェクトにはない可能性が広がります。

最初の2つのトピックについては、以降のセクションで説明します。3番目のトピックはクラスの定義で説明します。

このセクションの内容:

型チェック
戻り型と引数型
継承クラスに対する静的な型定義


型チェック

静的な型定義によって追加情報が提供されるため、コンパイラは次の2つの状況下において、より適切な型チェックサービスを行うことができます。

代入するオブジェクトのクラスが、代入先の変数のクラスと同じであるか、そのクラスを継承する場合には、代入を行っても警告は出ません。次の例は、これを示しています。

Shape     *aShape;
Rectangle *aRect;
 
aRect = [[Rectangle alloc] init];
aShape = aRect;

ここで、RectangleはShapeの一種である(RectangleクラスはShapeを継承する)ため、aRectaShapeに代入することができます。ただし、2つの変数の役割を逆にしてaShapeaRectに代入した場合、コンパイラが警告を発します。すべてのShapeがRectangleであるとはかぎらないからです(図 1-2も参照してください。この図は、ShapeとRectangleを含むクラス階層を示しています)。

代入演算子のどちらかの側にある式がidである場合は、チェックが行われません。静的に型定義したオブジェクトをidに自由に代入したり、idを静的に型定義したオブジェクトに自由に代入することができます。allocinitのようなメソッドはidを返すため、コンパイラは静的に型定義した変数に対して互換性のあるオブジェクトが返されることを保証しません。次のコードはエラーが起きる可能性はありますが、指定は可能です。

Rectangle *aRect;
aRect = [[Shape alloc] init];

戻り型と引数型

一般に、異なるクラスで同じセレクタ(同じ名前)を持つメソッドは、戻り型と引数型も同じでなければなりません。この制約は動的バインディングを可能にするためにコンパイラによって課せられます。メッセージレシーバのクラス(そして実行を要求されるメソッドに関するクラス固有の詳細)はコンパイル時には分からないため、コンパイラは同じ名前のメソッドをすべて同様に処理する必要があります。コンパイラがランタイムシステムのためにメソッドの戻り型と引数型に関する情報を準備する際に、メソッドセレクタごとにメソッド記述を1つだけ作成します。

しかし、メッセージを静的に型定義したオブジェクトに送信する場合、コンパイラはレシーバのクラスを認識しています。コンパイラはメソッドに関するクラス固有の情報にアクセスできます。したがって、メッセージは戻り型と引数型に関する制限から解放されます。

継承クラスに対する静的な型定義

インスタンスは、自身のクラスまたは継承元のクラスに静的に型定義することができます。たとえば、すべてのインスタンスをNSObjectとして静的に型定義できます。

ただし、コンパイラは型指定のクラス名にのみ基づいて、静的に型定義されたオブジェクトのクラスを把握し、それに従って型チェックを実行します。したがって、インスタンスを継承クラスとして型定義すると、コンパイラが実行時に起こると予測したことと、実際に起こることとの間に矛盾が生じる可能性があります。

たとえば、RectangleインスタンスをShapeとして静的に型定義する場合、次のようになります。

Shape *myRect = [[Rectangle alloc] init];

この場合、コンパイラはRectangleをShapeとして処理します。ここでRectangleメソッドを実行するメッセージをオブジェクトに送信します。

BOOL solid = [myRect isFilled];

この場合、コンパイラがエラーを報告します。isFilledメソッドはShapeクラスではなく、Rectangleクラスで定義されているからです。

しかし、今度はShapeクラスが認識するメソッドを実行するメッセージを送信したとします。

[myRect display];

Rectangleがメソッドをオーバーライドしていても、コンパイラはエラーを報告しません。しかし実行時には、Rectangleバージョンのメソッドが実行されます。

同様に、Upperクラスで、doubleを返すworryメソッドを宣言したとします。

- (double)worry;

また、UpperのMiddleサブクラスでメソッドをオーバーライドし、新しい戻り型を宣言します。

- (int)worry;

インスタンスをUpperクラスとして静的に型定義した場合、コンパイラはworryメソッドがdoubleを返すと予測し、インスタンスをMiddleクラスとして型定義した場合、worryintを返すと予測します。MiddleインスタンスをUpperクラスとして型定義すると、明らかにエラーが生じます。コンパイラは、オブジェクトに送信されるworryメッセージがdoubleを返すことをランタイムシステムに通知しますが、実行時には実際に返されるのがintなのでエラーが発生します。

静的な型定義は、名前が同じメソッドを、同じ戻り型と引数型を持たなければならないという制限から解放しますが、確実に実行できるのはメソッドがクラス階層の異なる分岐で宣言されている場合だけです。



< 前ページ次ページ >


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