2015-05-23 4 views
0

В предыдущем вопросе (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 

Просто хотел бы обернуться вокруг этого.

спасибо.

ответ

2

Наследование класса похоже на специализацию.

Подумайте о классе Person.

человек знает, как дыхание, ходить, говорить, кормить себя и т.д. (Так скажем, у всех людей есть метод MakeMeASandwich.)

Человек может иметь специализированную работу: плотник, повар, сантехник, IT человек, водитель грузовика и т.д.

Если у вас есть переменная

Person *aPerson; 

это указатель на Person. Вы не знаете, какую профессию он делает, вы просто знаете, что это Человек. Вы можете назначить объект Plumber этой переменной или объект Carpenter или любое другое специализированное Лицо, потому что все эти типы также относятся к общему классу Person.

Когда вы обращаетесь к aPerson, компилятор понятия не имеет, с какими людьми он разговаривает.

Компилятор может знать, что он может сказать Человеку сделать бутерброд и предположить, что все люди знают, как это сделать. (Все специализированные классы Person, как Карпентер и Водопроводчик наследует метод makeMeASandwich от своего родительского класса Person.)

Если вы не скажете компилятор:

«Лицо является Carpenter», то компилятор будет жаловаться, если вы просите Личность построить вам колоду, потому что ваш средний Человек не имеет метода buildADeck. У этого метода есть только люди типа Carpenter.

Когда вы говорите

[(Carpenter *)aPerson buildADeck] 

Вы рассказываете компилятор «Лицо является Карпентер. Поверьте мне. Я знаю. Попросите его/ее, чтобы построить палубу.» Компилятор предполагает, что вы знаете, о чем говорите, и что этот Человек действительно является Карпентером. Он попросит Человека построить колоду.

Если во время выполнения объект Person, на который указывает переменная aPerson, не относится к типу Carpenter, программа выйдет из строя, потому что, когда вы сообщите шеф-кондитеру, чтобы построить колоду, он/она будет очень смущен и не знаю, что делать. Он может даже рассердиться и уйти.

Если вы говорите:

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

Вы сообщаете компилятору создать Карпентера, и сохранить его в переменной общего назначения «Человек». Компилятор незамедлительно забывает, что созданный им человек был Карпентером. Он просто знает, что это Человек.

Таким образом, компилятор будет ли жаловаться, если вы пытаетесь сказать

[aPerson buildADeck]; 

Вы должны сказать

[(Carpenter *)aPerson buildADeck] 

Но, поскольку все люди знают, как сделать бутерброд, вы можете сказать,

[aPerson makeMeASandwich] 

и имейте это в виду. Даже если Человек является водопроводчиком, он/она будет знать, как сделать сэндвич, и, надеюсь, сделает вас одним. Вероятно, это будет лучший сэндвич, если Человек будет поваром, но, по крайней мере, вы получите бутерброд.

вы можете также сказать

сантехник * aPlumber = [[сантехник Alloc] инициализации]; [aPlumber makeMeASandwich];

потому что Сантехники тоже люди, и знаете, как сделать бутерброды. (IN OOP terms, Plumbers наследуют метод makeMeASandwich от их родительского класса Person.)

+0

Красноречивый, как всегда. Для меня это денежная линия: «Вы говорите компилятору о создании Плотника и храните его в переменной« Человек »общего назначения. Компилятор незамедлительно забывает, что созданный им человек был Карпентером. Он просто знает, что это Человек. Кристально ясно - спасибо. Извините, но есть _but_. В предыдущем посте, в вашем альтернативном решении, была цель назначить объект _ (метка, например) _ переменной UIView _control_: 'control = aLabel;'? Разве это еще не нужно было бы отличать как ярлык, чтобы получить доступ к свойствам метки? – iSofia

+0

У вас есть оператор switch, который возвращает различные типы объектов UIView. В некоторых случаях он возвращает метку, в других случаях - кнопку. Поскольку все объекты UIView, вы можете сохранить любой из них в переменной типа UIView. Это было мое понимание вашей цели ... решить, какой тип объекта создать. –

+0

Хорошо; Я вижу сейчас. Большое спасибо Дункан; искренне ценим вашу помощь в этих двух длинных постов. – iSofia

3

Это объектно-ориентированные концепции 101.

Вы писали: «Проще говоря, почему суперкласс не наследуют свойства подкласса, который был специально назначенным ему».

Потому что это наоборот. Подкласс наследует свойства своего суперкласса.

Подкласс представляет собой специализированную версию суперкласса. Суперкласс может иметь несколько подклассов. Подкласс знает о своих специализированных функциях, а также об общественных особенностях своего суперкласса. Но суперкласс не знает НИЧЕГО о любых подклассах, созданных из него. Как это могло быть? Подкласс мог существовать в совершенно отдельной библиотеке, написанной годами позже совершенно другим человеком.

В вашем конкретном образце кода у вас есть UILabel, который является специализированным UIView. UIView ничего не знает о каких-либо специальных особенностях UILabel.

Когда вы пытаетесь сделать:

view.text = @"some text"; 

компилятор жалуется, потому что он смотрит на определение для UIView и не находит свойство с именем text. Таким образом, вы получаете ошибку компиляции.

Поскольку вы не знаете, что во время выполнения view будет на самом деле быть направлен на UILabel, вы могли бы обмануть компилятор, используя бросок:

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

или записать его, используя сеттер синтаксис:

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

С помощью броска вы говорите компилятору: «Поверьте мне, я знаю, что это выглядит как переменная UIView, но я действительно знаю, что это переменная UILabel».

Вот важная записка об использовании актера. Вы обманываете компилятор. Вы можете ошибаться. Если вы ошибаетесь, ваше приложение, скорее всего, потерпит крах во время выполнения.

+0

И, очевидно, быть компилятором * слепота *, точечная нотация не будет работать? – iSofia

+0

Извините, я не знаю, что вы имеете в виду. Просто помните, что точечная нотация - это всего лишь сокращение для использования синтаксиса реального синтаксиса или метода getter. – rmaddy

+0

Да, это так. Очень удобно. Спасибо. – iSofia

1

У меня нет знания Objctive-C, а также для общего вопроса:

Думай об этом так - как бы пользователь суперкласса (или на самом деле - компилятор или линкер) знают, что у него есть эти свойства?На него ссылается тип суперкласса, поэтому для всех целей и целей - это суперкласс (несмотря на полиморфизм, поскольку он является механизмом времени исполнения).

1

Это не столько о наследовании, сколько о том, что вы сказали компилятору, и в этом случае view имеет тип UIView *. Вы можете назначить все, что захотите, этой переменной (если это подкласс или вы делаете компилятор счастливым).

Таким образом, компилятор считает, что это UIView *, даже если он на самом деле указывает на экземпляр UILabel, поэтому компилятор счастлив только с UIView методами и свойствами.

Если вы бросили, то компилятор будет счастлив, и во время выполнения все станет беспорядочным, если вы лжете компилятору.

Смежные вопросы