我有一个Person
对象,它包含name
、email
、birthdate
等。
我还有一个Person
的子类,叫做Member
,它包含yearJoined
、title
等。
在我的代码中,如何获取现有的Person
并将其转换为Member
?例如:
Member *mem = self.person;
由于类不匹配,我收到了编译器错误。但是子类应该继承其父类的所有属性,所以我正在寻找一种方法,只说"这个Person
对象现在应该是Member
对象。">
这有道理吗?
一种方法是在Member
类中声明initWithPerson
类方法和memberFromPerson
静态方法:
@interface Member : Person
{
NSString *title;
...
}
- (id)initWithPerson:(Person *)aPerson title:(NSString *)aTitle;
+ (Member *)memberFromPerson:(Person *)aPerson title:(NSString *)aTitle;
@end
在您的实施中:
@implementation Member
- (id)initWithPerson:(Person *)aPerson title:(NSString *)aTitle
{
if (self = [super initWithName:aPerson.name email:aPerson.email birthdate:aPerson.birthdate])
{
self.title = aTitle;
}
return self;
}
+ (Member *)memberFromPerson:(Person *)aPerson title:(NSString *)aTitle
{
return [[Member alloc] initWithPerson:aPerson title:aTitle];
}
@end
然后,当您想将Person
实例转换为Member
时,只需要调用:
Member *newMember = [Member memberFromPerson:myPerson title:@"New member!"];
当然,您可以根据是否需要title或year等其他变量来自定义所有这些(如果您正确初始化了所有内容,则可以创建不带任何其他参数的memberFromPerson:
版本)。
面向对象的三个最重要的属性中有两个是多态性和继承性。
给定一个类a,继承允许您创建一个从a继承的类B,这意味着B继承了a中实现的所有数据成员和方法,此外,它还使您能够:
- 重写A中定义的方法,专门化其行为
- 添加新方法和数据成员
多态性允许在需要其超类A的地方使用继承的类B。
当你从A继承B时,B">知道"A是什么。事实并非如此,因为A不知道从它继承了多少类以及哪些类。因此,它不能表现得像是继承者的实例。
在您的案例中,Member
是从Person
继承而来的,因此Member
可以用于任何需要Person
实例的地方。但相反的情况是不可能的,除非您知道这在您的代码中发生:
Member *member = [[Member alloc] init];
Person *person = member; // This is ok, person is a superclass of member
...
...
Member *member2 = (Member *) person; // This, although stylistically questionable, is possible because you know person is an instance of Member
因此,当您100%确定它是Member
的实例时,即使保持在Person
类型的变量中,也可以从Person
强制转换为Member
。
在以下情况下:
Person *person = [[Person alloc] init];
Member *member = (Member *) person;
编译器不会抱怨,但很可能会收到运行时异常。
为了明确这个概念,让我做一个简单的比较。MobilePhone
是一个基类,SmartPhone
从中继承。MobilePhone
有一些功能(你可以拨打和接听电话、发送和接收短信等)。SmartPhone
的行为就像MobilePhone
,所以你可以像使用MobilePhone
一样使用它,但你也可以做更多的事情,比如从AppStore安装应用程序(顺便提一下,"MobilePhone"是iPhone;-))、发送推文、阅读电子邮件、查看日历、天气等。所有这些都不能由MobilePhone
来完成。
作为一种变通方法,@Romain提出的(好的)解决方案是一种广泛使用的常见模式。但您必须注意的是,它不是强制转换,Member
的新实例是用从Person
复制的数据创建的。在某些情况下,了解这一点非常重要。