objective-cクラスメソッドの使い方で、多重定義のところが腑に落ちなかったのですが、一応氷解したので、記録として。
C++ の場合、次のようにメソッドの多重定義ができます。
1 2 3 4 5 6 | class A { public : void print( int x ); void print( char *s ); }; |
int型の引数を持つ場合と、char*型の引数を持つ場合の関数を「print」という同じ名前が使えるわけです。C言語の場合は「printInt」、「printString」なんて名前を変えないといけないので、この多重定義は名前を定義する際に非常に重要な機能なのです。
これを、「素直」にobjective-c の文法に直そうとすると、
1 2 3 4 | @interface A : NSObject - ( void )print:( int )x ; - ( void )print:( char *)s ; @end |
と書きたいところですが、、、できません。名前が重複してる(duplicate declaration of method ‘-print:’)なるエラーが出ます。
実は、objective-cのメソッドの書き方は、
– メソッド名 :(型)仮引数 :(型)仮引数 ;
なのかと思い込んでいたのですが、実は違います。
最初の単語も含めて、キーワードと仮引数のペアなんですなぁ。
– キーワード:(型)仮引数 キーワード:(型)仮引数 ;
と考えるのが正しいのです。
で、objective-cの場合は、型の違いをチェック判別せずに、キーワードの違いで判別します。そんな訳で、
– print:(int)x :(int)y ;
– print:(int)x z:(int)z ;
の2つはキーワード無しと、キーワードあり「z」のメソッドとして違いが認識されます。
ですが、最初のキーワードと型のペア
– print:(int)x;
– print:(char*)s;
の2つは、同じ print というキーワードを使っているので「重複(duplicate)」ってな訳で、コンパイルエラーになるのです。
# objective-c のサンプルコードを見て、妙なメソッドの名前の付け方をしてる
# なあ、と思っていたら、そういう理由があったんですね…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | #import <stdio.h> #import <Foundation/Foundation.h> #import <Foundation/NSObject.h> @interface A : NSObject - ( void )print ; //- (void)print :(void) ; // できない - ( void )print:( int )x ; //- (void)print:(char*)s ; // 重複するためできない - ( void )print:( int )x :( int )y ; - ( void )print:( int )x z:( int )z ; // キーワードで区別できる @end #if 0 // C++の場合 class A { public : // void print(); void print( void ); // print()と同じ意味 void print( int x ); void print( char *s ); void print( int x, int y ); // void pritn( int x, int z ); // できない }; #endif @implementation A - ( void )print { printf ( "in print\n" ); } - ( void )print:( int )x { printf ( "in print x\n" ); } - ( void )print:( int )x :( int )y { printf ( "in print x y\n" ); } /* - (void)print:(char*)s { printf("in print s\n" ); } */ - ( void )print:( int )x z:( int )z { printf ( "in print x z\n" ); } @end int main( void ) { printf ( "hello3.m\n" ); A *a = [A new ]; [a print]; [a print :1]; [a print :1 :2 ]; [a print :1 z:2 ]; [a release]; return 1; } /** 実行結果 hello3.m in print in print x in print x y in print x z **/ |
そんな訳で、ひとつの引数だけの場合は、実質、多重定義ができません。C言語のように「printInt」、「printString」としてメソッド名で区別をさせます。
# 実に「対称性」が悪い!と思うのは私だけではないハズ。
# ただ、objective-cの発祥時期を考えると、Cリンケージの考慮から、こういう形に
# なっているのだと思う。リンカーに対して厳密な名前を使うC++に対して(C言語自体
# のリンケージはかなり緩い)、objective-cはそのままC言語のリンクを使うように
# したので、こういう結果になったのでは?