Шрифт:
При работе с внешними переменными можно объявлять переменную как extern во многих местах, но определить ее можно только один раз. Рассмотрим программу как пример использования внешних переменных. Мы определили класс с именем Foo и ввели следующий код в файл main.m: #import "Foo.h" int gGlobalVar = 5; int main (int argc, char *argc[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; Foo *myFoo = [[Foo alloc] init]; NSLog (@"%i", gGlobalVar); [myFoo setgGlobalVar: 100] NSLog (@"%i", gGlobalVar); [myFoo release]; [pool drain]; return 0; }
Определение глобальной переменной gGlobalVar в этой программе делает ее значение доступным для любого метода (или функции), где используется соответствующее объявление extern. Предположим, что используется метод класса Foo с именем setgGlobalVar:. -(void) setgGlobalVar: (int) val { extern int gGlobalVar; gGlobalVar = val; }
Программа выведет следующие результаты. 5 100
Таким образом, метод setgGlobalVar: может выполнять доступ к внешней переменной gGlobalVar и изменять ее значение.
В тех случаях, когда доступ к значению gGlobalVar требуется многим методам, проще включить объявление extern только один раз в начале файла. Но если доступ к этой переменной требуется одному методу или небольшому числу методов, то имеет смысл включать объявления extern в каждый из таких методов; это сделает программу более организованной и ограничит использование конкретной переменной теми функциями, в которых она действительно требуется. Отметим, что если переменная определена внутри файла, содержащего код, который выполняет доступ к этой переменной, то отдельные объявления extern не требуются. Статические переменные
Только что показанный пример нарушает принцип инкапсуляции данных и практику надежного объектно-ориентированного программирования. Но вам может потребоваться работа с переменными, значения которых должны быть доступны для вызова из различных методов. Может показаться, что нет смысла делать переменную gGlobalVar переменной экземпляра в классе Foo, надежнее «скрыть» ее в классе Foo путем ограничения доступа к ней методами-установщиками (setter) и методами-получателями (getter), определенными для этого класса.
Теперь вы знаете, что любая переменная, определенная вне метода, является не только глобальной, но и внешней переменной. Но существует много ситуаций, когда нужно определить переменную, которая является глобальной, но не является внешней. Иначе говоря, вам нужно определить глобальную переменную, которая будет локальной для определенного модуля (файла). Имеет смысл определять такую переменную, если доступ к ней требуется только тем методам, которые содержатся в конкретном определении класса. Это можно сделать, определив переменную как статическую (static) внутри файла, содержащего секцию implementation для конкретного класса.
Если следующий оператор помещен вне любого метода (или функции), то значение gGlobalVar будет доступно из любой последующей точки файла, содержащей это определение, но будет недоступно из методов или функций, содержащихся в других файлах. static int gGlobalVar = 0;
Напомним, что методы класса не имеют доступа к переменным экземпляра (подумайте, почему это относится к данному случаю). Но вам может потребоваться, чтобы какой-либо метод класса имел доступ к переменным и мог задавать их значения. В качестве простого примера можно указать метод класса, выделяющий память для объектов (alloc), который должен следить за числом объектов. Это можно сделать, создав статическую переменную внутри файла секции implementation для этого класса. Метод, выделяющий память для объектов, может выполнять непосредственный доступ к этой переменной, поскольку она не будет переменной экземпляра. Пользователям данного класса необязательно знать об этой переменной. Поскольку она определена как статическая переменная в файле секции implementation, ее область действия будет ограничена этим файлом, поэтому пользователи не будут иметь непосредственного доступа к этой переменной и концепция инкапсуляции данных не будет нарушена. Вы можете написать метод для считывания значения этой переменной, если требуется доступ извне этого класса.
В программе 10.2 определение класса Fraction расширяется за счет добавления двух новых методов. Метод класса allocF выделяется память для нового объекта типа Fraction и следит за числом дробей (объектов Fraction), которые он выделил, а метод count возвращает значение этого счетчика. Метод count тоже является методом класса. Его можно было бы реализовать как метод экземпляра, но лучше запросить класс, сколько экземпляров он выделил, вместо передачи сообщения определенному экземпляру этого класса.
Ниже приводятся объявления для двух новых методов класса, добавленные в файл Fraction.h. +(Fraction *) allocF; +(int) count;
Отметим, что здесь не замещается наследуемый метод alloc; вместо этого определяется наш собственный метод выделения памяти. В этом методе будет использоваться наследуемый метод alloc. Следующий код нужно поместить в файл секции implementation Fraction.m. static int gCounter; @implementation Fraction +(Fraction *) allocF { extern int gCounter; ++gCounter; return [Fraction alloc]; } +(int) count { extern int gCounter; return gCounter; } // здесь находятся другие методы из класса Fraction @end