如果self能够存储基类实例,那么当我们返回self时,它是如何转换为派生实例的。
答案 0 :(得分:4)
这就是我认为你在问的问题:假设我们有一个基类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;
无论它做什么,它必须满足新实例适合在旧实例所在的任何地方使用的约束,基于其动态类型。
答案 1 :(得分:2)
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 init
,它也调用它的超级init
,因此层次结构中的每个类都会调用它的构造函数。
因此,没有任何变换 - 它只是一个指向已存在对象的指针,你可以返回它(99.9%的时间)或替换另一个对象。
请注意,还有第二个隐藏参数,即选择器_cmd
,在这种情况下等于@selector(initWithString:)
。如果您需要当前的方法名称,也可以使用它,例如用于调试日志记录。
答案 2 :(得分:0)
此处超级实例未分配给派生实例。 self = [super init];
就像告诉运行时系统在超类-init
方法中查找超类方法选择器表的init方法一样,self
就像支持这两个超类一样和派生类。在目标c中,包含类继承..只有实例变量是重复的。方法由层次结构中的所有类共享。如果你覆盖..你应该做self = [super init]
;这将引导您使用NSObject -init
方法。如果我们从超类中重写-init...
方法,请确保首先调用超级-init...
。这就是我的理解。谢谢。