自己が基本クラスのインスタンスを格納できる場合、自己を返すときに、どのように派生インスタンスに変換されるか。
3 に答える
これがあなたが求めていることだと思います: 基本クラス Base とサブクラス Derived があるとします。-[Derived init]
別のインスタンスを呼び出し-[Base init]
て返す場合-[Base init]
、その別のインスタンスはのインスタンスでBase
あり、そうでないDerived
ため不適切ではないでしょうか? たとえば、新しいオブジェクトにはDerived
、クラスに追加された可能性のあるインスタンス変数がありません。
答えは、それBase
を行うことは許可されていません。元のインスタンスを置き換える場合は、その元のインスタンスの動的な型を尊重する方法で行う必要があります。たとえば、次のようなことができます。
// Re-allocate with 100 extra bytes
id newSelf = NSAllocateObject([self class], 100, [self zone]);
[self release];
self = newSelf;
// ... continue to initialize ...
return self;
または、元のクラスの新しいサブクラスを動的に生成し、その新しいクラスの新しいインスタンスを割り当てる場合もあります。
NSString* newClassName = [NSString stringWithFormat:"%@_DynamicSubclass", NSStringFromClass([self class])];
Class newClass = objc_allocateClassPair([self class], [newClassName UTF8String], 0);
// ... further configure the new class, by adding instance variables or methods ...
objc_registerClassPair(newClass);
id newSelf = [newClass alloc];
[self release];
self = newSelf;
// ... continue to initialize ...
return self;
それが何をするにしても、その動的な型に基づいて、新しいインスタンスが古いインスタンスがあった場所で使用するのに適しているという制約を満たす必要があります。
self
隠しメソッド引数です:
// this Objective-C
- (id) initWithString:(NSString*)str;
// gets implemented like this C function would be
- (objc_object*) Foo_initWithString(Foo* self, SEL _cmd, NSString* str);
alloc
これは、最も派生したオブジェクトを保持するのに十分な大きさのメモリ ( で割り当てられる) へのポインタです。最も派生したクラスは super'sinit
を呼び出し、これはその super's も呼び出すinit
ため、階層内の各クラスはそのコンストラクターを呼び出します。
したがって、何も変換されません — 既存のオブジェクトへのポインタにすぎません。それを返す (99.9% の確率) か、代わりに別のオブジェクトを置き換えることができます。
2 番目の隠し引数、セレクターがあることに注意してください。_cmd
この場合、セレクターは に等しくなり@selector(initWithString:)
ます。デバッグ ロギングなど、現在のメソッド名が必要な場合にも使用できます。
ここでは、スーパーインスタンスは派生インスタンスに割り当てられていません。self = [super init];
これは、ランタイムシステムにスーパークラスメソッドセレクタテーブルのinitメソッドを探すように指示するようなものです...スーパー-init
メソッド内でself
は、スーパークラスと派生クラスの両方をサポートするようなものです。Objective cでは、クラスの継承の場合、インスタンス変数のみが複製されます。メソッドは、階層内のすべてのクラスで共有されます。uがオーバーライドする場合..uは実行する必要がありself = [super init]
ます; これにより、uはNSObject-init
メソッドになります。-init...
スーパークラスのメソッドをオーバーライドする場合は、スーパー-init...
が最初に呼び出されることを確認してください。これは私が理解していることです。ありがとうございました。