我想检查一下子类的以下实现在目标C中是否正确。
为父超类写的第一个代码:
#import "Employee.h"
@implementation Employee
-(id)init
{
return [self initEmployee:(NSString *)@"" withId:(NSString *)0];
}
-(id)initEmployee:(NSString *)theName withId:(NSString *)theId
{
self = [super init];
if (self) {
_name = theName;
_EmpId = theId;
}
return self;
}
@end
然后是子类。
#import "FullTimeEmp.h"
@implementation FullTimeEmp
-(id)init
{
return [self initEmployee:(NSString *)@""
withId:(NSString *)@""
andSalary:(NSNumber *)0
withBonus:(NSNumber *)0];
}
-(id)initEmployee:(NSString *)theName
withId:(NSString *)theId
andSalary:(NSNumber *)theSalary
withBonus:(NSNumber *)theBonus
{
self = [super initEmployee:(NSString *)theName withId:(NSString *)theId];
if (self) {
self.salary = theSalary;
self.bonus = theBonus;
}
return self;
}
@end
这样运行正常但我无法确认这是正确的方法,使用:
self = [super initEmployee:(NSString *)theName withId:(NSString *)theId];
在子类中继承超类部分(Name和ID),然后是子类部分,以指定子类添加(Salary和Bonus)来组成Full Time Employee对象。
我已经阅读了所有关于我们使用self = [super init]的原因,但很难找到如何在我拥有或在线的任何书籍中编写子类初始化的好例子。
答案 0 :(得分:0)
就初始化而言,你有正确的想法。你基本上只需要以某种方式正确初始化超类。你没有有这样做,你的子类基本上是你的超类和一些额外的成员,但在这种情况下它似乎是合适的。您可能有一个子类,例如,theId
或其他某个字段对于该子类总是相同的值,在这种情况下,您不需要将值传递给子类的初始值设定项。只要你以最适合你情况的方式初始化超类,你应该是好的。
但是,您似乎混淆了方法签名和方法调用或发送消息的语法。这样:
self = [super initEmployee:(NSString *)theName withId:(NSString *)theId];
和类似应该是这样的:
self = [super initEmployee:theName withId:theId];
当你定义一个方法时,你需要那些(NSString *)
的东西来告诉编译器你的每个参数是什么类型,但是当你调用方法/发送消息时你已经有了一个对象已经具有已知类型的参数,因此您不需要它。你在这里实际完成的是投射 NSString *
到NSString *
,这显然是多余的。
self.salary = theSalary;
代替:
_salary = theSalary;
假设您没有以不同的名称合成它。一个很好的理由是因为子类可以覆盖属性的setter方法,这可能导致非常不可预测的行为。通常,应避免在处于部分构造状态时向self
发送消息,因为这样做会产生副作用。显然,如果您正在设置由超类定义的属性并且您无权访问实例变量,或者您正在使用延迟初始化,那么您没有太多选择,只能使用setter(除了不是在这里初始化它),但这不是你在这个例子中所拥有的。
编辑2:此外,还有以下两点:
-(id)init
{
return [self initEmployee:(NSString *)@""
withId:(NSString *)@""
andSalary:(NSNumber *)0
withBonus:(NSNumber *)0];
}
首先,如果没有为这些事情设置默认值,那么您不必感到被迫提供直接init
方法。如果你没有名字也没有身份证的员工,那很好,但是如果你只使用实际数据初始化你的一个类是有意义的,那么不要因为没有覆盖init
而感到难过如果你真的想阻止人们使用它,甚至可以从中抛出异常。
其次,NSNumber
是一个对象,所以当你尝试为它指定一个直的0
时,它等同于将指针设置为nil
而不是创建一个对象,这可能不是你想要的。要实际创建值为零的NSNumber
s,您需要以与NSString
相同的方式使用文字,因此(同样在这里删除强制转换):
-(id)init
{
return [self initEmployee:@""
withId:@""
andSalary:@0
withBonus:@0];
}
或者只是使用常规int
代替NSNumber
,如果您根本不需要它们就是对象。
答案 1 :(得分:0)
作为OP中我的问题的更新,并帮助其他可能有同样混淆的人,我的代码根据给出的建议重新定义:
#import "Employee.h"
@implementation Employee
-(id)initEmployee:(NSString *)theName withId:(NSString *)theId
{
self = [super init];
if (self) {
_name = theName;
_EmpId = theId;
}
return self;
}
@end
和
#import "FullTimeEmp.h"
@implementation FullTimeEmp
-(id)initEmployee:(NSString *)theName
withId:(NSString *)theId
andSalary:(NSNumber *)theSalary
withBonus:(NSNumber *)theBonus
{
self = [super initEmployee:theName withId:theId];
if (self) {
_salary = theSalary;
_bonus = theBonus;
}
return self;
}
-(NSNumber *)calcPay
{
NSNumber *pay;
pay = [NSNumber numberWithFloat:([self.salary floatValue] + [self.bonus floatValue])];
return pay;
}
@end