Оператор Dot (“.”) И стрелка (“->”) используют в C против Objective-C
Я пытаюсь склонить голову к некоторым различиям в использовании и синтаксисе в C против Objective-C. В частности, я хочу знать, как (и почему) использование отличается для оператора точки и оператора стрелки в C по сравнению с Objective-C. Вот простой пример.
C Код:
// declare a pointer to a Fraction struct Fraction *frac; ... // reference an 'instance' variable int n = (*frac).numerator; // these two expressions int n = frac->numerator; // are equivalent
Код Objective-C:
- значение «ссылки» и «разыменование»,
- Возвращающий указатель от функции
- Разница между использованием указателей символов и массивов символов
- Неинициализированные указатели в коде
- Используя оператор равенства == для сравнения двух строк для равенства в C
// declare a pointer to a Fraction Fraction *frac = [[Fraction alloc] init]; ... // reference an instance variable int n = frac.numerator; // why isn't this (*frac).numerator or frac->numerator??
Таким образом, видя, как в обеих программах один и тот же файл (то есть он является указателем на объект или структуру фракции), почему они используют другой синтаксис при доступе к свойствам? В частности, в C свойство numerator
получает доступ с помощью frac->numerator
, но с Objective-C он обращается к оператору точек с помощью frac.numerator
. Поскольку frac
является указателем в обеих программах, почему эти выражения отличаются друг от друга? Может ли кто-нибудь помочь прояснить это для меня?
- Crash или «segmentation fault», когда данные копируются / отсканированы / прочитаны неинициализированному указателю
- Где хранятся функции-члены для объекта?
- Где в памяти строковые литералы? стек / куча?
- Почему этот код segfault на 64-битной архитектуре, но отлично работает на 32-битной?
- Функция для динамического выделения матрицы
- Не удается найти модуль 'angleular2 / angular2'
- Почему в C ++ не существует ссылки на член?
- В чем разница между C # Reference и указателем?
frac
на самом деле не одинакова в обеих программах.
AC Fraction
– это struct
, которая является базовым типом без перегруженных операторов и действительно может быть сконструирована и разрушена по умолчанию. Если вы определяете функции или поля в структуре, способ доступа к этим свойствам в C
является оператором точки ( .
). Objective-C поддерживает этот оператор, когда вы используете struct
s. Для удобства вы можете выполнить операцию разыменования и точки с помощью оператора стрелки ( ->
) (упомянутые два эквивалентных выражения). Objective-C также сохраняет это при доступе к struct
s.
Однако в вашем примере Fraction
Objective-C, возможно, (предположительно) указала хотя бы id
типа, который является просто именем classа и указателем на экземпляр этого classа под капотом. Он также, скорее всего, будет подclassом NSProxy
или NSProxy
. Эти classы Objective-C отличаются тем, что у них есть целый уровень предопределенных операций поверх всего C
структуры (если вы действительно хотите в нее вникнуть, тогда вы можете взглянуть на ссылку Objective-C Runtime Reference ). Также важно отметить, что Objective-C-class всегда является указателем .
Одной из основных операций является objc_msgSend
. Когда мы работаем над этими типами объектов, компилятор Objective-C интерпретирует оператор точки ( .
) Или синтаксис квадратной скобки ( [object method]
) как objc_msgSend
метода objc_msgSend
. Более подробную информацию о том, что на самом деле происходит здесь, см. В этой серии статей Билла Бумгарнера, инженера Apple, который курирует разработку среды выполнения Obj-C.
Оператор стрелки ( ->
) на самом деле не должен использоваться для объектов Objective-C. Как я уже сказал, экземпляры classа Objective-C представляют собой C-структуру с добавленным дополнительным слоем связи, но этот уровень связи существенно обойден, когда вы используете стрелку. Например, если вы откроете Xcode и введите в [UIApplication sharedApplication]->
а затем перечислите список завершения метода, вы увидите следующее:
Здесь вы можете увидеть кучу нормальных полей, к которым мы обычно обращаемся с синтаксисом с квадратной скобкой (например, [[UIApplication sharedApplication] delegate]
). Однако эти конкретные элементы являются полями C
которые сохраняют значения соответствующих свойств Objective-C.
Итак, вы можете примерно подумать об этом так:
Оператор Dot на объекте C
- (во время выполнения) Возвращаемое значение поля
Оператор стрелки на объекте C (указатель)
- Указатель разыменования
- Возвращаемое значение поля
Оператор точки / квадратные скобки объекта Objective-C (указатель)
- (во время компиляции) Заменить на вызов
objc_msgSend
- (во время выполнения) Посмотрите определение classа Obj-C, исключите исключение, если что-то пошло не так
- Указатель разыменования
- Возвращаемое значение поля
Оператор стрелки объекта Objective-C (указатель)
- (во время выполнения) Указатель разыменования
- Возвращаемое значение поля
Теперь я определенно упрощаю здесь, но резюмирую: операторы стрелок, похоже, делают в обоих случаях одно и то же, но оператор точки имеет дополнительное / различное значение в Objective-C.
Точечная обозначение – это выбор дизайна. Поскольку мы всегда имеем дело с указателями на экземпляры objc, я бы предположил, что дизайнеры хотели что-то знакомое, что также не нарушало бы существующие программы. Он был введен в ObjC 2 – всего несколько лет назад. До этого вам всегда приходилось использовать скобки для обмена сообщениями.
Точечная нотация имеет значение, хотя – это не прямой доступ, а сообщение .
То есть:
obj.property = val; // is the same as: [obj setProperty:val]; // and not: obj->property = val; val = obj.property; // is the same as: val = [obj property]; // and not: val = obj->property;
Вы все равно можете написать obj->ivar
для доступа к указателю на элементы объекта (если видимо).
В вашем первом примере Fraction
является структурой. Во втором примере Fraction
является classом Objective-C (а в iOS, вероятно, будет подclass NSObject
).
C ++ не допускает перегрузки operator .
, Поэтому без дополнительной информации вы можете сделать вывод о том, что точечное обозначение, которое вы видите, является дополнительной языковой конструкцией, интегрированной в Objective-C, а не с определенным или перегруженным оператором C / C ++.
Так как это происходит, точечное обозначение представляет собой просто конструктивную особенность, которую разработчики выбрали как стенографию для доступа к свойствам, полностью эквивалентную элементу с квадратной скобкой:
myObjCVar.prop == [myObjCVar prop];
Точечный оператор на объектах является специальным синтаксисом для доступа к свойствам объектов. Он вызывает геттер или сеттер объекта за кулисами. Так, например, [@"hello" length]
и @"hello".length
эквивалентны *. Для всех остальных типов точка совпадает с точкой C, а стрелка всегда одна и та же.
* Примечание. Метод доступа не всегда будет называться так же, как и свойство. Если это объявленное свойство, и объявление обозначает специальный метод getter или setter, тот будет использоваться вместо этого.
Точечные и стрелочные обозначения одинаково одинаковы для C, как в Objective-C (строгий суперсет). Я думаю, что принципиальное отличие, которое нужно различить, – это различие между структурой и объектом Objective-C.
Точечная нотация, используемая для объектов Objective-C, используется для свойств, которые были введены в Objective-C 2.0. Тем не менее, с помощью структур, -> и точечные обозначения между Objective-C и C одинаковы.