3

私は Objective-C の学習を始めたばかりで、 Stephen G. KochanによるProgramming in Objective-C 3rd Editionを読んでいます。

ポリモーフィズムのメカニズムを説明する段落があります。

実行時に、Objective-C ランタイム システムは、dataValue1 (id オブジェクト) 内に格納されているオブジェクトの実際のクラスをチェックし、正しいクラスから適切なメソッドを選択して実行します。ただし、より一般的なケースは、コンパイラはメソッドに引数を渡したり、その戻り値を処理したりするための間違ったコードを生成します。これは、たとえば、一方のメソッドが引数としてオブジェクトを取り、もう一方のメソッドが浮動小数点値を取った場合に発生します。または、たとえば、一方のメソッドがオブジェクトを返し、もう一方のメソッドが整数を返した場合。2 つのメソッド間の矛盾がオブジェクトの型の違いだけである場合 (たとえば、Fraction の add: メソッドは引数として Fraction オブジェクトを取り、それを返し、Complex の add: メソッドは Complex オブジェクトを取り、返すなど)、コンパイラは次のことを行います。いずれにせよ、メモリ アドレス (つまり、ポインター) はオブジェクトへの参照として渡されるため、正しいコードが生成されます。

段落の最初の部分で、同じ名前で異なる型の引数を持つ異なるクラスで 2 つのメソッドを宣言すると、コンパイラが間違ったコードを生成する可能性があると述べていることはよくわかりません。段落の最後の部分では、同じ名前で引数と戻り値の型が異なる2つのメソッドを使用しても問題ないと述べています...ああ、いや...

次のコードがあり、コンパイルして正常に実行されます。

@implementation A
- (int) add:(int)a {
    return 1 + a;
}
@end
@implementation B
- (int) add: (B*) b {
    return 100;
}
@end
id a = [[A alloc] init];
id b = [[B alloc] init];
NSLog(@"A: %i, B %i", [a add:100], [b add:b]);

編集:私が引用したテキストのように、上記のコードはエラーを引き起こすはずですが、いくつかの警告メッセージしか生成しません.「add:」という名前の複数のメソッドが見つかりました. 「id」を「int」型のパラメータに送信する整数変換への互換性のないポインタ

私は Java と C++ のバックグラウンドを持っています。Objective-C のポリモーフィズムがこれらの言語のポリモーフィズムとは少し異なることは知っていますが、不確実性についてはまだ混乱しています (太字のテキスト)。

私は何かを誤解しているに違いないと思います。私とそれを必要とする人のために、Objective-C の動的バインディングについて詳しく説明していただけますか?

ありがとうございます!

4

2 に答える 2

6

これらの2つのメソッドは、たとえばx86_64 ABIで同じ呼び出しセマンティクスを持っているため、異常なことに気づいていません。ポインターは整数と見なすことができ、x86_64 ABIでは、同じ方法でターゲットメソッドに渡されます。

ただし、別のクラスがある場合、例:

@implementation C
- (int)add:(float)number {
    return (int)number + 100;
}
@end

解析時に浮動小数点引数(Kochanが述べたように)を受け取り、次にコンパイラーを受け取ります。

id a = [[A alloc] init];
id b = [[B alloc] init];
id c = [[C alloc] init];
NSLog(@"A: %i, B %i, C %i", [a add:100], [b add:b], [c add:100]);

x86_64ABIで指定されている浮動小数点レジスタに[c add:100]配置する必要があることを知りません。100したがって、-[C add:]浮動小数点引数が浮動小数点レジスタにあることを期待する、は、引数に対応しない値を読み取り100ます。

それが機能するためには、静的型で変数を宣言する必要があります。

C *c = [[C alloc] init];

または、メッセージを送信するときに正しいタイプにキャストします。

[(C *)c add:100];

結局のところ、Objective-Cメッセージの送信は関数呼び出しです。異なるABIは、変数引数、浮動小数点対整数引数または戻り値、またはスカラー算術型の代わりに構造体を使用して関数を呼び出すための異なるセマンティクスを持っている場合があります。コンパイラがターゲットABIに従って異なる方法で処理される異なるメソッドシグネチャを認識し、利用可能なタイプ情報が十分でない場合、間違ったメソッドシグネチャを選択してしまう可能性があります。

于 2011-11-06T04:54:50.427 に答える
3

後者の場合、違いは引数のクラスのみであるため、区別が行われます。Complex*Fraction*はどちらもポインタであるため、同じ名前の 2 つのメソッドが混同されても問題はありません。

一方、あなたの例の状況は危険です.1つの引数はポインタであり、もう1つはint. ただし、これについて安全であることは簡単です。

NSLog(@"A: %i, B %i", [(A*)a add:100], [(B*)b add:b]);
于 2011-11-06T04:25:56.233 に答える