Главная » iPhone, Objective-C, Программирование для iOS и MacOS » Наследование Objective-C

0

При создании класса Person мы объявили его субклассом NSObject. Это означает, что каждый экземпляр Person будет содержать методы и переменные экземпляров, определенные в NSObject, а также методы и переменные экземпляров, определенные в Person. Говорят, что Person наследует методы и переменные экземпляров от NSObject. В этом разделе мы изучим наследование более подробно.

Откройте проект BMIТime и создайте новый файл: класс Objective-C с именем Employee, являющийся субклассом NSObject. Вскоре мы изменим класс Employee и сделаем его субклассом Person. Вполне логично, верно? Работник (Employee) является разновидностью человека (Person). У них есть рост и вес. Тем не менее не каждый человек является работником. Мы также включим в наш класс переменную экземпляра, относящуюся к нашему конкретному классу, – табельный номер работника.

наследует от     наследует от     наследует от          наследет от

Рис. 18.1. Диаграмма наследования некоторых знакомых классов

Откройте файл Employee.h. Импортируйте Person.h, замените суперкласс на Person и добавьте переменную экземпляра для хранения табельного номера работника:

#import "Person.h"

@interface Employee : Person

{

int employeeID;

}

@property int employeeID;

@end

Откройте Employee.m и синтезируйте методы доступа:

#import "Employee.h"

@implementation Employee

@synthesize employeeID;

@end

Теперь у нас имеется новый класс Employee, содержащий все переменные экземпляров Person и новую переменную экземпляра с именем employeeID. Экземпляры Employee отвечают на те же сообщения, что и экземпляр Person. Кроме того, экземпляры Employee отвечают на сообщения setEmployeeID: и employeeID.

Так как класс Person является субклассом NSObject, Employee наследует все методы и переменные экземпляров NSObject. Все объекты наследуют (прямо или косвенно) от NSObject.

Класс NSObject содержит много методов, но только одну переменную экземпляра: указатель isa. Указатель isa каждого объекта ссылается на класс, его создавший.

Допустим,  вы  отправили  объекту  сообщение  fido.  Чтобы  ответить  на  это

сообщение, объект при помощи указателя isa определяет свой класс и спрашивает: "Есть ли у тебя метод экземпляра с именем fido? Если в классе существует метод экземпляра fido, то он выполняется. Если у класса такого метода нет, он спрашивает у своего суперкласса: «Есть ли у тебя метод экземпляра с именем fido? Так поиск метода с именем fido продолжается вверх 1\0 самого начала цепочки. Поиск прекращается при обнаружении метода fido или достижении последнего звена. В начале  цепочки  класс  NSObject говорит:  «Нет,  метода  fido у  меня  нет»,  а  вы

получаете сообщение об ошибке – что-то типа «Экземпляр Employee не отвечает на селектор fido».

Рис. 18.2. Диаграмма объектов BMITime

Попробуйте  сами  –  откройте  файл  main.m  и  отправьте  экземпляру  Person

сообщение, которое он не поймет:

int main(int argc, const char * argv[])

{

@autoreleasepool {

// создание экземпляра Person

id person = [[Person alloc] init];

// присваивание значений переменным экземпляров [person setWeightInKilos:96];

[person setHeightInMeters:1.8];

// вызов метода bodyMassIndex  float bmi = [person bodyMassIndex];

NSLog(@"person (%d, %f) has a BMI of %f",

[person weightInKilos], [person heightInMeters], bmi);

[person count];

}

return 0;

}

Постройте  и  запустите  программу.  (На  предупреждение  компилятора  не

обращайте внимания, потому что мы делаем это сознательно. В большинстве случаев на предупреждение обязательно стоит отреагировать!) На консоль выводится сообщение об исключении времени выполнения:

*** Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘-[Person count]: unrecognized selector sent to instance 0x100108de0′

Просмотрите описание исключения и удалите проблемную строку, прежде чем продолжать.

Мы создали новый класс Employee, но еще не использовали его. Измените файл

main.m, чтобы в нем использовался класс Employee:

#import <Foundation/Foundation.h>

#import "Employee.h"

int main(int argc, const char * argv[])

{

@autoreleasepool {

// создание экземпляра Person

Person * person = [[Employee alloc] init];

// присваивание значений переменным экземпляра [person setWeightInKilos:96];

[person setHeightInMeters:1.8];

// вызов метода bodyMassIndex  float bmi = [person bodyMassIndex];

NSLog(@"person (%d, %f) has a BMI of %f",

}

return 0;

}

Обратите внимание: переменная person по-прежнему объявляется как указатель на Person. Не создаст ли это проблем? Постройте и запустите программу – вы увидите, что она работает нормально. Дело в том, что работник (Employee) является частным случаем человека (Person) – он может сделать все, что может человек Таким образом, мы можем использовать экземпляр Employee везде, где программа ожидает получить экземпляр Person.

Но сейчас мы используем метод, уникальный для Employee, поэтому тип переменной-указателя  придется  изменить:

#import <Foundation/Foundation.h>

#import "Employee.h"

int main(int argc, const char * argv[])

{

@autoreleasepool {

// создание экземпляра Person

Employee *person = [[Employee alloc] init];

// присваивание значений переменным экземпляра [person setWeightInKilos:96];

[person setHeightInMeters:1.8];

[person setEmployeeID:15];

// вызов метода bodyMassIndex  float bmi = [person bodyMassIndex];

NSLog(@"Employee %d has a BMI of %f", [person employeeID], bmi);

}

return 0;

}

Источник: Аарон Хилегас, «Objective-C. Программирование для iOS и MacOS», 2012 г.

По теме:

  • Комментарии