Type Check

朝起きると雪が2cm程積もっていた。何年ぶりかなあ。もっともお昼までにはすっかり消えてしまっていた。

「isbn:978-4797346800:title」(荻原剛志)、04-02 型の静的なチェック:

使われるクラスが確定している場合には、クラス名を明示した型宣言を行うことによって、メッセージが処理可能かどうかをコンパイル時にチェックできる。

#import <Foundation/Foundation.h>

@interface A : NSObject
- (void)whoAreYou;
@end

@implementation A
- (void)whoAreYou { printf("I'm A\n"); }
@end

@interface B : A
- (void)whoAreYou;
- (void)sayHello;
@end

@implementation B
- (void)whoAreYou { printf("I'm B\n"); }
- (void)sayHello { printf("Hello\n"); }
@end

@interface C : NSObject
- (void)printName;
@end

@implementation C
- (void)printName { printf("I'm C\n"); }
@end

int main (int argc, const char * argv[]){
  NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
  A *a, *a2;
  B *b;
  C *c;

  a = [[A alloc] init];
  a2 = [[B alloc] init];
  c = [[C alloc] init];
  b = a;            // warning: assignment from distinct Objective-C type
                    // 導出クラスへのポインタに基本クラスのポインタを代入したため警告
  [a whoAreYou];    // --> I'm A
  [a2 whoAreYou];   // --> I'm B
                    // クラスAへのポインタ変数だが、実際にはクラスBのポインタが
                    // 代入されているのでクラスBのメソッドが呼び出される
  [a2 sayHello];    // warning: 'A' may not respond to '-sayHello'
                    // --> Hello
                    // クラスAのポインタ変数に何が代入されているかに関わらず
                    // クラスAには'-sayHello'メソッドがないため警告が出る
  //[c whoAreYou];  // warning: `C' may not respond to '-whoAreYou'
                    // もちろんクラスCには'-whoAreYou'メソッドがないため警告が出る
                    // そして実行時にはエラーになる
  [(B*)a2 sayHello];// --> Hello
                    // クラスAへのポインタをクラスBへのポインタにキャストしているので
                    // '-sayHello'を呼び出せる
  [(B*)a whoAreYou];// --> I'm A;
                    // いくらキャストしたからといっても実体はクラスAのオブジェクトなので
                    // クラスAのメソッドが呼び出される
  [pool drain];
  return 0;
}