了解对象继承

时间:2015-05-23 16:00:34

标签: objective-c class object inheritance

在上一个问题(linked here)中,有一些关于对象继承的未解决问题仍然不清楚。 (我对术语的使用可能不正确 - 请相应编辑 - 谢谢)

简单地说,为什么超类不会继承已明确赋给它的子类的属性。代码示例:

UIView *view = nil;
UILabel *label = [[UILabel alloc] init];
label.text = @"some text...";
view = label;

// view has not inherited any UILabel properties
view.text = @"new text...";              //error
view.textColor = [UIColor redColor];     //error

我想了解一下这个问题。

谢谢。

4 个答案:

答案 0 :(得分:3)

这是面向对象的概念101.

您写道:“简单地说,为什么超类不会继承已明确分配给它的子类的属性”

因为它恰恰相反。子类继承其超类的属性。

子类是超类的专用版本。超类可以有几个子类。子类知道其特殊功能以及其超类的公共功能。但是一个超类知道从它创建的任何子类的NOTHING。怎么可能呢?子类可以存在于一个完全独立的库中,该库在几年后由完全不同的人编写。

在您的特定示例代码中,您有UILabel,这是一个专门的UIViewUIViewUILabel的任何专业功能一无所知。

当你尝试:

view.text = @"some text";

编译器抱怨,因为它查看UIView的定义,但找不到名为text的属性。所以你得到一个编译错误。

由于您碰巧在运行时知道view实际上会指向UILabel,您可以使用强制转换来欺骗编译器:

((UILabel *)view).text = @"some text";

或使用setter语法编写它:

[(UILabel *)view setText:@"some text"];

通过使用演员你告诉编译器 - “相信我,我知道它看起来像UIView变量,但我真的知道它是UILabel变量”。

这是关于使用演员表的重要说明。你在欺骗编译器。你可能错了。如果您错了,那么您的应用很可能会在运行时崩溃。

答案 1 :(得分:2)

类继承就像专门化一样。

想想班级人物。

一个人知道如何呼吸,走路,说话,喂养自己等等(所以,让我们说所有人都有MakeMeASandwich方法。)

一个人可能有一份专门的工作:木匠,厨师,水管工,IT人员,卡车司机等。

如果您有变量

Person *aPerson;

它是指向Person的指针。你不知道这个人做了什么交易,你只知道它是一个人。您可以将Plumber对象分配给该变量,Carpenter对象或任何其他专用Person,因为所有这些类型也属于通用类Person。

当你提到aPerson时,编译器不知道它与谁交谈的是什么类型的人。

编译器可能知道它可以告诉Person制作一个三明治,并假设所有人都知道如何做到这一点。 (所有专门的Person类,如Carpenter和Plumber都从其父类Person继承makeMeASandwich方法。)

除非你告诉编译器:

"此人是木匠"然后编译器会抱怨如果你要求人为你建立一个套牌,因为你的普通人没有buildADeck方法。只有Carpenter型人才有这种方法。

当你说

[(Carpenter *)aPerson buildADeck]

你告诉编译器"这个人是木匠。相信我。我知道。让他/她建造一个甲板。"编译器假设你知道你在说什么,那个人真的是一个木匠。它会要求该人建立一个套牌。

如果在运行时,事实证明aPerson变量指向的Person对象不是Carpenter类型,程序将崩溃,因为当你告诉糕点厨师建造一个套牌时,他/她会很困惑不知道该怎么办。他/她甚至可能会生气并退出。

如果你说:

Person *aPerson = [[Carpenter alloc] init];

您告诉编译器创建一个Carpenter,并将其存储在一个通用的" Person"变量。编译器立即忘记它创建的人是Carpenter。它只知道它是一个人。

因此,如果您尝试说

,编译器会抱怨
[aPerson buildADeck];

你必须说

[(Carpenter *)aPerson buildADeck]

但是,既然所有人都知道如何制作三明治,你可以说

[aPerson makeMeASandwich] 

并让它工作。即使这个人是水管工,他/她也会知道如何做三明治,并且(希望)会让你成为一个三明治。如果这个人是厨师,它可能是一个更好的三明治,但至少你会得到一个三明治。

你也可以说

Plumber * aPlumber = [[Plumber alloc] init];    [aPlumber makeMeASandwich];

因为管道工也是人,并且知道如何制作三明治。 (根据OOP术语,管道工从其父类Person继承makeMeASandwich方法。)

答案 2 :(得分:1)

我不了解Objctive-C,但至于一般性问题:

以这种方式思考 - 超类(或者确实 - 编译器或链接器)的用户如何知道它具有这些属性?它被超类类型引用,因此对于所有意图和目的 - 它是超类(尽管是多态,因为它是运行时机制)。

答案 3 :(得分:1)

这不是关于继承,而是关于你告诉编译器的内容,在这种情况下,view属于UIView *类型。你可以为这个变量分配你想要的任何东西(只要它是一个子类,或者你让编译器开心)。

因此,编译器认为它是UIView *,即使它实际上指向UILabel的实例,因此编译器只对UIView方法和属性感到满意。

如果你强制转换,那么编译器会很高兴,并且在运行时,如果你对编译器撒谎,事情就会变得混乱。