Использование оператора точки (".") И оператора стрелки ("->") в 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:
// 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??
Итак, видя, как frac
одинаковы в обеих программах (т. е. это указатель на объект или структуру Fraction), почему они используют разный синтаксис при доступе к свойствам? В частности, в С, numerator
свойство доступно с frac->numerator
, но с Objective-C, к нему можно обратиться с помощью оператора точки, с frac.numerator
, поскольку frac
указатель в обеих программах, почему эти выражения отличаются? Кто-нибудь может помочь уточнить это для меня?
5 ответов
frac
на самом деле не то же самое в обеих программах.
переменный ток Fraction
это struct
, который является базовым типом без перегруженных операторов и действительно может быть создан и уничтожен по умолчанию. Если вы определяете функции или поля в структуре, способ доступа к этим свойствам в C
с точкой (.
) оператор. Objective-C поддерживает этот оператор при использовании struct
s. Для удобства вы можете выполнить операцию разыменования и точки с помощью стрелки (->
) (два эквивалентных выражения, которые вы упомянули). Objective-C также сохраняет это при доступе struct
s.
Цель-C Fraction
в вашем примере, однако, вероятно (можно предположить) указатель по крайней мере типа id
, который является просто именем класса и указателем на экземпляр этого класса под капотом. Это также очень вероятно, будет подкласс NSObject
или же NSProxy
, Эти классы Objective C особенные в том, что они имеют целый слой предопределенных операций поверх просто C
struct (если вы действительно хотите углубиться в это, вы можете взглянуть на Objective-C Runtime Reference). Также важно отметить, что класс Objective-C всегда является указателем.
Одна из самых основных операций objc_msgSend
, Когда мы оперируем этими типами объектов, компилятор Objective-C интерпретирует точку (.
) оператор или синтаксис квадратной скобки ([object method]
) как objc_msgSend
вызов метода. Для получения более подробной информации о том, что на самом деле происходит здесь, см. Эту серию постов Билла Бумгарнера, инженера Apple, который наблюдает за разработкой среды выполнения Obj-C.
Стрелка (->
) оператор не должен использоваться на объектах Objective-C. Как я уже говорил, экземпляры класса Objective-C - это структура C с добавленным дополнительным уровнем связи, но этот уровень связи по существу обходится, когда вы используете стрелку. Например, если вы откроете Xcode и наберете [UIApplication sharedApplication]->
и затем вызвать список завершения метода, вы видите это:
Здесь вы можете увидеть несколько нормальных полей, к которым мы обычно обращаемся с помощью синтаксиса в квадратных скобках (например, [[UIApplication sharedApplication] delegate]
). Эти конкретные пункты, однако, являются C
поля, в которых хранятся значения их соответствующих свойств Objective-C.
Итак, вы можете примерно представить это так:
Точечный оператор на объекте C
- (во время выполнения) Возвращаемое значение поля
Оператор стрелки на объекте C (указатель)
- Указатель разыменования
- Возвращаемое значение поля
Точечный оператор / квадратные скобки на объекте Objective C (указатель)
- (во время компиляции) Заменить на вызов
objc_msgSend
- (во время выполнения) Посмотрите определение класса Obj-C, выведите исключение, если что-то пошло не так
- Указатель разыменования
- Возвращаемое значение поля
Оператор стрелки на объекте Objective-C (указатель)
- (во время выполнения) Указатель разыменования
- Возвращаемое значение поля
Теперь я определенно упрощаю здесь, но подведу итог: операторы стрелок, по-видимому, делают в основном одно и то же в обоих случаях, но оператор точки имеет дополнительное / другое значение в Objective-C.
Дот-нотация - это выбор дизайна. Поскольку мы всегда имеем дело с указателями на экземпляры объектов, я бы предположил, что дизайнеры хотели чего-то знакомого, что также не сломало бы существующие программы. Он был представлен в 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
класс Objective-C (и в iOS, скорее всего, подкласс NSObject
).
C++ не допускает перегрузки operator .
, Поэтому без дополнительной информации вы можете сделать вывод, что точка, которую вы видите, представляет собой дополнительную языковую конструкцию, интегрированную в Objective-C, а не определенный или перегруженный оператор C/C++.
Так получилось, что точечная нотация - это просто конструктивная особенность, которую разработчики выбрали как сокращение для доступа к свойству, полностью эквивалентное получателю квадратной скобки:
myObjCVar.prop == [myObjCVar prop];
Оператор точки на объектах - это специальный синтаксис для доступа к свойствам объектов. Он вызывает геттер или сеттер свойства за кулисами. Так, например, [@"hello" length]
а также @"hello".length
эквивалентны *. Для всех других типов точка совпадает с точкой C, а стрелка всегда одинакова.
* Примечание: метод доступа не всегда будет называться так же, как свойство. Если это объявленное свойство и в объявлении указан специальный метод get или setter, он будет использоваться вместо этого.
Обозначения точек и стрелок одинаково одинаковы в C и Objective-C (строгая надмножество). Я думаю, что фундаментальное различие, которое необходимо различать, - это различие между структурой и объектом Objective-C.
Точечная запись, используемая для объектов в Objective-C, используется для свойств, представленных в Objective-C 2.0. Однако в случае структур -> и точка обозначения между Objective-C и C одинаковы.