Использование оператора точки (".") И оператора стрелки ("->") в 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]-> и затем вызвать список завершения метода, вы видите это:

Список внутренних ivars для объекта Obj-C при использовании оператора со стрелкой

Здесь вы можете увидеть несколько нормальных полей, к которым мы обычно обращаемся с помощью синтаксиса в квадратных скобках (например, [[UIApplication sharedApplication] delegate]). Эти конкретные пункты, однако, являются C поля, в которых хранятся значения их соответствующих свойств Objective-C.

Итак, вы можете примерно представить это так:

Точечный оператор на объекте C

  1. (во время выполнения) Возвращаемое значение поля

Оператор стрелки на объекте C (указатель)

  1. Указатель разыменования
  2. Возвращаемое значение поля

Точечный оператор / квадратные скобки на объекте Objective C (указатель)

  1. (во время компиляции) Заменить на вызов objc_msgSend
  2. (во время выполнения) Посмотрите определение класса Obj-C, выведите исключение, если что-то пошло не так
  3. Указатель разыменования
  4. Возвращаемое значение поля

Оператор стрелки на объекте Objective-C (указатель)

  1. (во время выполнения) Указатель разыменования
  2. Возвращаемое значение поля

Теперь я определенно упрощаю здесь, но подведу итог: операторы стрелок, по-видимому, делают в основном одно и то же в обоих случаях, но оператор точки имеет дополнительное / другое значение в 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 одинаковы.

Другие вопросы по тегам