Вы не говорите, почему вы удивлены поведением, но одна возможность заключается в разнице между статическим и динамическим поиском и вводом метода.
Первыйобратите внимание, что с наследованием везде, где у вас есть ссылка Parent
, у вас действительно может быть Child
один - последний может делать все, что может первый, и может заменить один.
Теперьво многих объектно-ориентированных языках, например C ++, типизирование переменных и поиск методов основаны на статических (то есть объявленных) типах.Так, например, в C ++ ваша переменная c
считается экземпляром Child
, а когда метод вызывается в c
, компилятор C ++ определяет, какой метод вызывать, основываясь только на этом.Поэтому присвоение экземпляра Parent
является небезопасным - у такого экземпляра нет методов Child
, и обязательно произойдет сбой.Вы можете сделать присвоение безопасным в C ++, используя приведение:
Parent *p;
Child *c;
...
c = (Child *)p;
Приведение проверяет во время выполнения, является ли объект, на который ссылается p
, Child
(или любой класс, который наследуется от Child
и т.д.) и выдаст ошибку, если нет.Поскольку это делается во время выполнения, оно обычно заключено в условное выражение, которое сначала проверяет, является ли p
Child
.
. Однако в Obj-C метод поиска выполняется динамически во время выполнения.основанный на фактическом типе ссылочного объекта, а не на типе переменной, которая на него ссылается.В результате этого, если ваша переменная c
содержит ссылку на Parent
и вы пытаетесь вызвать метод Child
, вы получите ошибку времени выполнения (которая будет чистой, в случае C ++ ваш код будетвероятно, просто неисправность и / или взрыв).
Этот динамический характер Obj-C позволяет легко пропустить множество ошибок программирования, причем они становятся очевидными только при запуске кода - и так как это очень сложнополностью протестировать приложение после отправки кода клиентам.Поэтому компилятор Obj-C выполняет как можно больше проверок типов, чтобы помочь минимизировать количество ошибок, оставшихся во время выполнения.Однако, опять же из-за динамического характера, он иногда будет только предупреждать , а не сообщать о ошибке и отказываться от компиляции - как это было в вашем примере.
Решение в Obj-C такое же, как и в C ++ выше - используйте приведение, чтобы указать, что объект должен быть определенного типа и защитить его условным условием:
Parent *p;
Child *c;
...
if([p isKindOfClass:[Child class]) // we need a Child
{
c = (Child *)p;
...
}
else
{ // handle p not being a Child
...
}
Вышеприведенное намеренно не обсуждает относительные преимуществаи недостатки динамические по сравнению с статические , вы лучше прочитаете это из хорошей книги.