GNUstepでobjective-cを学ぶ(2)

objective-cクラスメソッドの使い方で、多重定義のところが腑に落ちなかったのですが、一応氷解したので、記録として。

C++ の場合、次のようにメソッドの多重定義ができます。

class A
{
public:
void print( int x );
void print( char *s );
};

int型の引数を持つ場合と、char*型の引数を持つ場合の関数を「print」という同じ名前が使えるわけです。C言語の場合は「printInt」、「printString」なんて名前を変えないといけないので、この多重定義は名前を定義する際に非常に重要な機能なのです。

 

これを、「素直」にobjective-c の文法に直そうとすると、

@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 のサンプルコードを見て、妙なメソッドの名前の付け方をしてる
# なあ、と思っていたら、そういう理由があったんですね…

#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言語のリンクを使うように
# したので、こういう結果になったのでは?

カテゴリー: 開発, Objective-C パーマリンク