为什么可以定义一个具有超类类型的变量,但是为它分配一个子类的对象?

时间:2009-05-08 12:54:52

标签: c objective-c

对我来说,这仍然不完全清楚。例如:

NSArray * arr = [[NSMutableArray alloc] init];

我的意思是......是的,它有效。但是:为什么我可以告诉编译器“嘿,我的var只是一个NSArray,你只需要保留空间以便它适合那里”然后,实际上,有一个大的,胖的NSMutableArray进入那个有道路的地方更多的方法,更多的实例变量,只需要更多的空间。我的意思是......这怎么可能?

我会理解另一种方式:左侧是大胖子NSMutableArray,右侧是小型NSArray。根据我的理解,超类总是比子类更小,更复杂。子类可能会覆盖一些东西,但它也可能会添加一些东西。正确?

想象一下,你买了一个车库,因为你的妻子通过电话告诉你,她买了一些可以开车的东西。然后,它不仅仅是你想象的小型车。她买了一辆大卡车。它不适合那里。

那么我怎么能想到这一点,把它放在脑海里呢? ;)

这适用于社区维基,只是因为其他人也感到困惑。

7 个答案:

答案 0 :(得分:5)

对象大小与它无关,因为赋值仅指定引用(可以将其视为内存地址)。引用的大小是固定的,与对象大小无关。

答案 1 :(得分:5)

我认为你错误的关键点是相信变量包含对象,编译器会为它们预留空间。

在Objective-C中,与Java一样,变量只包含对象的引用 - 编译器的参与在那里结束。对象本身存在于称为堆的内存区域中,该区域由运行时维护。

答案 2 :(得分:2)

在您的示例中,子类的大小无关紧要,因为您正在为堆上的大胖子类分配内存,然后将指针存储在指向超类的指针中。

为了纠正你的比喻,你告诉别人要为你妻子的车建造一个足够大的车库。而你所做的就是指出车库的位置。你可能指着一个大车库或一个小车库,这对你没关系,因为你只是把你的妻子指向车库的地方,其他人负责确保车库足够大。

答案 3 :(得分:2)

在我看来,你对这方面的两个方面感到困惑。一个与空间分配有关,其他一些答案已经解决了。总而言之,在面向对象的系统中声明引用不会分配空间来保存该类型的对象,它只是分配空间来保存指针。

你似乎很困惑的另一个问题是,在面向对象的系统中输入实际意味着什么。

  

我会理解另一种方式:大   胖子NSMutableArray在左侧,和   微小的NSArray和右边。

将任何类视为包含两个单独的东西:一个接口,它是它公开的方法和成员集,以及一个实现,它确定对这些方法和成员实际执行的访问。

当您声明对NSArray的引用时,这意味着该引用将指向支持与NSArray相同的接口的对象。因为NSMutableArray是NSArray的子​​类,所以NSMutableArray的实例将始终支持NSArray的接口。因此,分配是安全的。

相反,如果声明对NSMutableArray的引用,它必须指向支持子类接口的对象。因此,您无法将指向NSArray实例的指针分配给该变量,因为NSArray不支持NSMutableArray的完整接口。 (在弱类型系统中,您可以执行赋值,但如果尝试调用接口中存在但不在实例化对象中的方法,则可能会出现运行时错误。我不知道有多强类型的Objective C是。)

答案 4 :(得分:1)

在更强类型的语言中,将指向子类对象的指针存储在已声明为基类的指针的变量中是完全正常的。但是,您无法访问任何子类的方法或成员变量。

目标-C的类型不是那么强烈,特别是w.r.t.消息调用,其中(AFAICR)没有类型检查,如果无法处理请求的消息,则会出现运行时错误或无操作。

答案 5 :(得分:1)

您忘记了类型系统。 NSArray是一个框架类,而不是语言原语。运行时系统正在维护信息。

答案 6 :(得分:1)

你是对的,因为子类通常比父类占用更多的空间。然而,这不是问题,因为子类根本不存储在数组中 - 存储在数组中的唯一内容是对实际对象的引用,它们总是具有相同的大小。

使用你的比喻,想象你有一些车库,你的妻子有她的车。显然这些车的尺寸不同,但这并不妨碍你列出每辆车的数量(你的妻子第一辆车被标记为1,接下来是2辆)以及那辆车当前停在哪里(你的妻子有这么多汽车,你必须保持自己的停车场编号)。这些车有不同的尺寸和不同的型号,但你仍然可以将它们全部写在列表中,它们仍然是所有车型,因此它们有一些共同之处(例如,你可以驱动它们,每个都可以获得如此多的mpg)。

面向对象编程的一个好处是可以使用子类代替它们的超类。