SlideShare a Scribd company logo
第11回iPhone輪講
CHAPTER04
CHAPTER04
オブジェクトの型と
動的結合
動的結合とは
実際のプログラミングでは様々なクラスのインスタンス
を使う事になる
‣ すべてのオブジェクトがid型で表されていると
「どのオブジェクトがどのクラスのインスタンス」か
わからなくなりやすい
動的結合とは
List4-1
動的結合とは
動的結合
このプログラムは端末から入力された数により
変数objに代入するオブジェクトのクラスが異なるよう
になっている
クラスA,BはwhoAreYouというメッセージに対応
できる
0を入力すると「I m A」が表示される
1を入力すると「I m B」が表示される
動的結合
クラスNSObjectではwhoAreYouを定義していない
ため対応できない
2を入力するとエラーが発生する
‣ しかしコンパイルできてしまう
動的結合
ObjCは『あるオブジェクトで,そのメッセージが処理
できるかどうか,どのように処理されるか』は,
オブジェクトへ実際にメッセージを送ったときに
決定される
動的結合
すべてのインスタンスは自分がどのクラスなのか
知っている
メッセージを受け取ったときにそれに応じた処理が
実行できる
逆にそのオブジェクトが受け取ったメッセージを
処理できないときにエラーが返る
動的結合
送られてきたメッセージに対応してどのメソッドが
実行されるのかが実行時に決定される方式を
動的結合(dynamic binding)あるいは,動的束縛と
呼ぶ
ポリモルフィズム
List4-1では変数objに代入されているインスタンスが
クラスA,クラスBどちらのものでも同じメッセージに
反応した
だが,その反応は代入されているインスタンスに
依存していた
ポリモルフィズム
同じメッセージを送っても,レシーバのオブジェクトに
応じて適切なメソッドが選ばれて実行される性質を
ポリモルフィズム(polymorphism)と呼ばれる
型としてのクラス
クラス名を型として使う
定義したクラスは新しい型として使える
オブジェクトは基本的にid型で表す
しかし特定のクラスのインスタンスであることを
明示する事もできる
クラス名を型として使う
あるクラスFooのインスタンスであることを
明示するには
という型を用いる事が出来る
この型はオブジェクとが代入される変数,
メソッドや関数の引数,返り値の型として
普通に使える
Foo *
クラス名を型として使う
例えば変数の宣言は,
これは「オブジェクトはポインタとして
表現されている」ということ
Volume *v;
MuteVolume *mute;
クラス名を型として使う
「オブジェクトがポインタとして表現さている」
代入によって変数v2はv1が指すものと
同じものを指す
printf()で出力される値は0でなく1になる
Volume *v1, *v2;
v1 = [[Volume alloc] initWithMin:0 max:10 step:1];
v2 = v1;
[v1 up];
printf(“%dn”, [v2 Value];
nil
空のポインタnil
ObjCでは何のオブジェクトも表していない
(ポインタが実体を何も指していない)ことを
表すのにnilという値を用意している
nil
nilはid型のポインタで値は0
イニシャライザが初期化に失敗した時に返す値はnil
インスタンスオブジェクトを新しく作成するとき
メソッドallocはインスタンス変数を0で初期化する
id型やその他オブジェクトへのポインタもnilで
初期化する
型の静的なチェック
オブジェクトをid型としてでなく,クラス名を明示して
宣言する
するとコンパイル時に型チェックが行える
構文上宣言したクラスと,そこに使われる
オブジェクトのクラスが一致しない場合警告を
表示する事が出来る
型の静的なチェック
ObjCで使われるクラスが確定している場合
クラス名を明示して型宣言を行う事によって
メッセージが処理可能かどうかをコンパイル時に
チェックできる
List4-2
型チェックの実験
List4-2
型チェックの実験
型の静的なチェック
このプログラムはクラスAとCは独立して定義され,
BはAのサブクラスとして定義されている
main関数の中で変数をクラス名を使って定義している
型の静的なチェック
コンパイルすると以下の警告が表示される
クラスCにはwhoAreYouメソッドが無い為
表示されている
型チェックは機能している
型の静的なチェック
main関数の中の変数の型を次のように変更し,
コンパイルする
警告は出なくなるが,実行するとエラーが返る
C *c; id c;
型の静的なチェック
メソッドの呼び出し部分を以下のように変更して
コンパイルする
これで実行できるようになる
実行結果は
[a whoAreYou];
[b whoAreYou];
[c whoAreYou];
[a whoAreYou];
[b whoAreYou];
[c printName];
型の静的なチェック
変数aもbもクラスAのインスタンスのとして型が
宣言されている
しかし特に警告が出ない
クラスAから継承した機能だけ使っている限り
クラスBのインスタンスも「Aのインスタンスだ」
と言う顔をして動作させる
型の静的なチェック
次に変数bのメソッド呼び出しを以下のようにする
という警告が出るが,問題なく動作する
[b whoAreYou]; [b sayHello];
型の静的なチェック
警告を出さないようにするには素直に変数bを
クラスBのインスタンスとして宣言すればよいが,
以下のような方法もある
変数bをクラスBのインスタンスとしてキャストし,
コンパイラをごまかしている
[(B*)b sayHello];
型の静的なチェック
最後に変数aはクラスAのインスタンスだが,
以下のようにキャストしたらどうなるか
実行すると「I m A」と出力される
実行されるメソッドがキャストによって静的に
決まるということはない
[(B*)a whoAreYou];
プログラミングにおける
型宣言
シグネチャが異なる場合
メッセージセレクタには引数や返り値の型の情報はな
いが,セレクタと型情報を合わせたものを
シグネチャ(signature)と呼ぶ
インタフェースでメソッド宣言に用いる以下のような
形式のことをシグネチャ呼ぶ事がある
- (id)cellAtRow:(int)row column:(int)col;
プログラミングにおける
型宣言
プログラム内のメソッド呼び出しには
メッセージセレクタが書かれているだけで,
引数や返り値の型まではわからない
セレクタが同じでも引数や返り値の型が異なる
メソッドがあった時はどうなるのか
プログラミングにおける
型宣言
次のインタフェースが宣言されていたとする
@interface X : NSOBject
- (int)value;
@end
@interface Y : NSObject
- (float)value;
@end
@interface Z : X
- (const char *)value;
@end
プログラミングにおける
型宣言
このとき以下のメッセージはコンパイルできてしまう
実際どんな値が返されるコードが生成されるのかは,
コンパイラ任せになってしまう
id obj;
...
a = [obj value];
プログラミングにおける
型宣言
以下のような場合どうなるか
この場合変数barは期待通りの結果が得られる
変数fooにはクラスZのインスタンスが代入されてい
る可能性がある
実行時に誤作動するかもしれない
X *foo;
Y *bar;
...
a = [foo value];
b = [bar value];
プログラミングにおける
型宣言
レシーバや引数となるオブジェクトの型が実行時に
決まってもよいとする以上,メッセージのシグネチャが
何通りも存在していたのでは正しくコンパイルできない
プログラミングにおける
型宣言
結局,ObjCにおいては基本的に,
『同じセレクタを持つメッセージは引数や返り値の型
(シグネチャ)を同じにすべきである』
と,結論づける事が出来る
クラスの前方宣言
あるクラスのインタフェース部を記述する際
インスタンス変数の型やメソッドの返り値,
引数の型として別のクラスを指定することがある
このような場合その型名がクラスである事を
どうやってコンパイラに知らせるのか?
クラスの前方宣言
1つの方法は,そのクラスのインタフェース部を含む
ヘッダファイルをインポートする
#import <Foundation/NSObject.h>
#import “Volume.h” //Volumeクラスのインタフェース部をインポート
@interface AudioPlayer : NSObject {
Volume *theVolume;
...
}
- (Volume *)volume;
...
クラスの前方宣言
ヘッダファイルにはクラス名の定義以外の様々な情報が
書かれていることもある
コンパイル時に必要以上に処理が重くなる事も
考えられる
クラス名を型として使うだけなら,「クラス名である」
という以上の情報は必要ない
クラスの前方宣言
以下のような書き方が出来る
@classというコンパイラ指示子で
「Volumeという識別子はクラス名である」という
事を宣言している
これをクラス名の前方宣言(forward declaration)
と呼ぶ
#import <Foundation/NSObject.h>
@class Volume; //Volumeというクラスを使う事を宣言
@interface AudioPlayer : NSObject
...
クラスの前方宣言
@classの後には「,」で区切って複数個書く事が出来る
末尾には「;」を置く
@classは何個でも書く事が出来る
@class NSString, NSArray, NSMutableArray;
@class Volume, MuteVolume
インスタンス変数の
情報隠蔽
インスタンス変数へのアクセス
これまでのプログラムの例ではインスタンス変数に
アクセスできるのは保持しているオブジェクト自体
ObjCでは基本的にはオブジェクトの外から
インスタンス変数へのアクセスを許可していない
インスタンス変数への
アクセス
しかし,クラスAのメソッド定義の中からクラスAの
self以外のインスタンスが持つインスタンス変数には
直接アクセスできる
アクセスできるかのチェックはコンパイル時に
行われる
インスタンス変数への
アクセス
インスタンス変数にアクセスするには,そのインスタン
スオブジェクトが静的に(クラス名を型として使って)
型宣言されていなければならない
インスタンス変数への
アクセス
インスタンスオブジェクトobjが持つ
インスタンス変数myvarにアクセスする
この記法はポインタで構造体のメンバにアクセスする
場合と同じ
obj -> myvar
インスタンス変数への
アクセス
次のプログラムは色の三原色を表現したクラスで
2つの色の中間の色を計算する機能が付いている
インスタンス変数への
アクセス
三原色クラスのインタフェース部
(RGB.h)
インスタンス変数への
アクセス
三原色クラスの実装部
(RGB.m)
インスタンス変数への
アクセス
三原色クラスの実装部
(RGB.m)
インスタンス変数への
アクセス
三原色クラスをテストするmainプログラム
(rgbmain.m)
インスタンス変数への
アクセス
メソッドblendColorの中で引数のオブジェクトに対して
「->」を使ってインスタンス変数を直接参照している
引数が同じクラスのインスタンスなので
この方法でアクセス可能
他のクラスのインスタンス(スーパークラスのイン
スタンスであっても)この方法では参照できない
クラスを使って型が宣言されていない場合でも
アクセスできない
インスタンス変数の可視性
インスタンスオブジェクトが持つインスタンス変数には
外部から直接アクセスしない方がよい
どうしてもアクセスしたい場合許可する方法がある
インスタンス変数の可視性
インスタンス変数の外部への見せ方(見せるかどうか,
範囲はどこまでか)を可視性(visibility)と呼ぶ
ObjCではインスタンス変数に3種類の可視性を指定
できる
インスタンス変数の可視性
@private
宣言したクラス内のみでアクセス可能
サブクラスからはアクセスできない
同じクラスのインスタンスなら,メソッド内で
->演算子を使ってアクセスできる
インスタンス変数の可視性
@protected
宣言したクラス,およびそのサブクラス内で
アクセス可能
同じクラスのインスタンスなら,メソッド内で
->演算子を使ってアクセスできる
通常何も指定していないインスタンス変数は
このモード
インスタンス変数の可視性
@public
どこからでも,構造体のメンバのようにして
参照できる
インスタンス変数の可視性
@private @protected @public
同じクラス内 ○ ○ ○
同じクラス内で->を使って ○ ○ ○
サブクラスから ○ ○
サブクラスから->を使って ○
どこからでも ○
インスタンス変数の可視性
可視性の指定はクラスのインタフェース部の
インスタンス変数の宣言部分で行う
インスタンス変数の宣言の先頭,あるいは宣言と宣言
の間(;の後)に3つのコンパイラ指示子のいずれかを
記述できる
インスタンス変数の可視性
コンパイラ指示子の可視性の指定は,
その位置からインスタンス変数の宣言が終わるまで
別のコンパイラ指示子が出現するまで
その間のインスタンス変数に対して有効になる
インスタンス変数の可視性
コンパイラ指示子の出現順序に制限は無い
また,何回現れても構わない
インスタンス変数の可視性
@interface TableOfColors : HashTable
{
id delegate; //protected
@public
BOOL empty; //public
@private
id cache; //private
int cache_entries; //private
@protected
int entries; //protected
}
...
@end
つづく(多分)

More Related Content

PPT
創業時を振り返って(起業家向け)Ver1.1
PDF
Midterm2nd
PDF
Objc03 1
PDF
Objc05
PDF
Objc04
PDF
Objc03 2
PDF
Objc01
PDF
Cocoa Pro09
創業時を振り返って(起業家向け)Ver1.1
Midterm2nd
Objc03 1
Objc05
Objc04
Objc03 2
Objc01
Cocoa Pro09

More from hasegawa (8)

PDF
Cocoa Pro08
PDF
Cocoa Pro07
PDF
Cocoa Pro6
PDF
Cocoa Pro5
PDF
Cocoa Pro4
PDF
Cocoa Pro01
PDF
Cocoa Pro03
PDF
CocoaPro02
Cocoa Pro08
Cocoa Pro07
Cocoa Pro6
Cocoa Pro5
Cocoa Pro4
Cocoa Pro01
Cocoa Pro03
CocoaPro02
Ad

Objc02