1629295407-c61bfe4caba98380ea3e7cdae6295416 (846200), страница 25
Текст из файла (страница 25)
В этом классе (назовем его Building)будут храниться три элемента информации о зданиях (количество этажей, общая площадь иколичество жильцов).Ниже представлена первая версия класса Building. В нем определены трипеременные экземпляра: floors, area и occupants. Обратите внимание на то, что классBuilding не содержит ни одного метода.
Поэтому пока его можно считать классомданных. (В следующих разделах мы дополним его методами.)class Building {public int floors; // количество этажейpublic int area; // общая площадь основания зданияpublic int occupants; // количество жильцов}Переменные экземпляра, определенные в классе Building, иллюстрируют общийспособ их объявления. Формат объявления переменной экземпляра такой:доступ тип имя_переменной;128Часть I. Язык C#Здесь элемент доступ представляет спецификатор доступа, элемент тип — типпеременной экземпляра, а элемент имя_переменной — имя этой переменной.
Такимобразом, если не считать спецификатор доступа, то переменная экземпляра объявляется также, как локальная переменная. В классе Building все переменные экземпляра объявленыс использованием модификатора доступа public, который, как упоминалось выше,позволяет получать к ним доступ со стороны кода, расположенного даже вне классаBuilding.Определение class создает новый тип данных. В данном случае этот новый типданных называется Building. Это имя можно использовать для объявления объектов типаBuilding. Помните, что объявление class — это лишь описание типа; оно не создаетреальных объектов. Таким образом, предыдущий код не означает существования объектовтипа Building.Чтобы реально создать объект класса Building, используйте, например, такуюинструкцию:Building house = new Building();// Создаем объект// типа Building.После выполнения этой инструкции house станет экземпляром класса Building,т.е. обретет “физическую” реальность.
Подробно эту инструкцию мы рассмотрим ниже.При каждом создании экземпляра класса создается объект, который содержитсобственную копию каждой переменной экземпляра, определенной этим классом. Такимобразом, каждый объект класса Building будет содержать собственные копиипеременных экземпляра floors, area и occupants. Для доступа к этим переменнымиспользуется оператор “точка” (.). Оператор “точка” связывает имя объекта с именем егочлена. Общий формат этого оператора имеет такой вид:объект.членКак видите, объект указывается слева от оператора “точка”, а его член — справа.Например, чтобы присвоить переменной floors значение 2, используйте следующуюинструкцию.house.floors = 2;В общем случае оператор “точка” можно использовать для доступа как к переменнымэкземпляров, так и методам.Рассмотрим полную программу, в которой используется класс Building.// Программа, в которой используется класс Building.using System;class Building {public int floors; // количество этажейpublic int area; // общая площадь основания зданияpublic int occupants; // количество жильцов}// Этот класс объявляет объект типа Building.class BuildingDemo {public static void Main() {Building house = new Building();// Создание объекта// типа Building.int areaPP; // Площадь, приходящаяся на одного жильца.// Присваиваем значения полям в объекте house.house.occupants = 4;house.area = 2500;house.floors = 2;Глава 6.
Введение в классы, объекты и методы129// Вычисляем площадь, приходящуюся на одного жильца дома.areaPP = house.area / house.occupants;}}Console.WriteLine("Дом имеет:\n " +house.floors + " этажа\n " +house.occupants + " жильца\n " +house.area +" квадратных футов общей площади, из них\n "+ areaPP + " приходится на одного человека");Эта программа состоит из двух классов: Building и BuildingDemo. Внутрикласса BuildingDemo метод Main() сначала создает экземпляр класса Building сименем house, а затем получает доступ к переменным этого экземпляра house,присваивая им конкретные значения и используя эти значения в вычислениях.
Важнопонимать, что Building и BuildingDemo — это два отдельных класса. Единственнаясвязь между ними состоит в том, что один класс создает экземпляр другого. Хотя этоотдельные классы, код класса BuildingDemo может получать доступ к членам классаBuilding, поскольку они объявлены открытыми, т.е. public-членами. Если бы в ихобъявлении не было спецификатора доступа public, доступ к ним ограничивался бырамками класса Building, а класс BuildingDemo не имел бы возможности использоватьих.Если предыдущую программу назвать UseBuilding.cs, то в результате еекомпиляции будет создан файл UseBuilding.exe.
Классы Building и BuildingDemoавтоматически становятся составными частями этого исполняемого файла. При еговыполнении получим такие результаты:Дом имеет:2 этажа4 жильца2500 квадратных футов общей площади, из них625 приходится на одного человекаВ действительности совсем не обязательно классам Building и BuildingDemoнаходиться в одном исходном файле.
Можно поместить каждый класс в отдельный файл иназвать эти файлы Building.cs и BuildingDemo.cs, соответственно. После этогонеобходимо дать компилятору команду скомпилировать оба файла и скомпоновать их.Для этого можно использовать следующую командную строку:csc Building.cs BuildingDemo.csЕсли вы работаете в среде Visual Studio IDE, нужно поместить оба файла в проект ивыполнить команду построения этого проекта.Прежде чем идти дальше, имеет смысл вспомнить основной принциппрограммирования классов: каждый объект класса имеет собственные копии переменныхэкземпляра, определенных в этом классе.
Таким образом, содержимое переменных в одномобъекте может отличаться от содержимого аналогичных переменных в другом. Междудвумя объектами нет связи, за исключением того, что они являются объектами одного итого же типа. Например, если у вас есть два объекта типа Building и каждый объектимеет свою копию переменных floors, area и occupants, то содержимоесоответствующих (одноименных) переменных этих двух экземпляров может быть разным.Следующая программа демонстрирует это.// Эта программа создает два объекта класса Building.using System;130Часть I. Язык C#class Building {public int floors; // количество этажейpublic int area; // общая площадь основания зданияpublic int occupants; // количество жильцов}// Этот класс объявляет два объекта типа Building.class BuildingDemo {public static void Main() {Building house = new Building();Building office = new Building();int areaPP; // Площадь, приходящаяся на одного жильца.// Присваиваем значения полям в объекте house.house.occupants = 4;house.area = 2500;house.floors = 2;// Присваиваем значения полям в объекте office.office.occupants = 25;office.area = 4200;office.floors = 3;}}// Вычисляем площадь, приходящуюся на одного жильца.areaPP = house.area / house.occupants;Console.WriteLine("Дом имеет:\n " +house.floors + " этажа\n " +house.occupants + " жильца\n " +house.area +" квадратных футов общей площади, из них\n " +areaPP + " приходится на одного человека");Console.WriteLine();// Вычисляем площадь, приходящуюся на одного// работника офиса.areaPP = office.area / office.occupants;Console.WriteLine("Офис имеет:\n " +office.floors + " этажа\n " +office.occupants + " работников\n " +office.area +" квадратных футов общей площади, из них\n " +areaPP + " приходится на одного человека");Вот каков результат выполнения этой программы:Дом имеет:2 этажа4 жильца2500 квадратных футов общей площади, из них625 приходится на одного человекаОфис имеет:3 этажа25 работников4200 квадратных футов общей площади, из них168 приходится на одного человекаГлава 6.
Введение в классы, объекты и методы131Как видите, данные о доме (содержащиеся в объекте house) совершенно не связаныс данными об офисе (содержащимися в объекте office). Эта ситуация отображена на рис.6.1.houseofficefloors2area2500occupants4floors3area4200occupants25Рис. 6.1. Переменные экземпляров не связаныСоздание объектовВ предыдущих программах с помощью следующей строки был объявлен объект типаBuilding. Building house = new Building();Это объявление выполняет две функции.
Во-первых, оно объявляет переменную сименем house классового типа Building. Но эта переменная не определяет объект, аможет лишь ссылаться на него. Во-вторых, рассматриваемое объявление создает реальнуюфизическую копию объекта и присваивает переменной house ссылку на этот объект. И всеэто — “дело рук” оператора new. Таким образом, после выполнения приведенной вышестроки кода переменная house будет ссылаться на объект типа Building.Оператор new динамически (т.е.
во время выполнения программы) выделяет памятьдля объекта и возвращает ссылку на него. Эта ссылка (сохраненная в конкретнойпеременной) служит адресом объекта в памяти, выделенной для него оператором new.Таким образом, в C# для всех объектов классов должна динамически выделяться память.Предыдущую инструкцию, объединяющую в себе два действия, можно переписать ввиде двух инструкций.Building house; // Объявление ссылки на объект.house = new Building();// Выделение памяти для объекта// типа Building.В первой строке объявляется переменная house как ссылка на объект типаBuilding. Поэтому house — это переменная, которая может ссылаться на объект, но несам объект. В этот момент (после выполнения первой инструкции) переменная houseсодержит значение null, которое означает, что она не ссылается ни на какой объект.
Послевыполнения второй инструкции будет создан новый объект класса Building, а ссылка нанего будет присвоена переменной house. Вот теперь ссылка house связана с объектом.Тот факт, что к объектам классов доступ осуществляется посредством ссылок,объясняет, почему классы называются ссылочными типами. Ключевое различие междутипами132Часть I.
Язык C#значений и ссылочными типами состоит в значении, которое содержит переменная каждоготипа. Переменная типа значения сама содержит значение. Например, после выполненияследующих инструкцийint x; x = 10;переменная x содержит значение 10, поскольку x — это переменная типа int, т.е.переменная типа значения. Но при выполнении инструкцииBuilding house = new Building();сама переменная house будет содержать не объект, а ссылку на этот объект.Переменные ссылочного типа и присвоение имзначенийВ операции присвоения ссылочные переменные действуют не так, как переменныетипа значений (например, типа int).
Присваивая одной переменной (типа значения)значение другой, мы имеем довольно простую ситуацию. Переменная слева (от оператораприсваивания) получает копию значения переменной справа. При выполнении аналогичной(казалось бы) операции присваивания между двумя переменными ссылочного типаситуация усложняется, поскольку мы изменяем объект, на который ссылается ссылочнаяпеременная, что может привести к неожиданным результатам. Например, рассмотримследующий фрагмент программы:Building house1 = new Building();Building house2 = house1;На первый взгляд может показаться, что house1 и house2 ссылаются на различныеобъекты, но это не так.
Обе переменные, house1 и house2, ссылаются на один и тот жеобъект. Присвоение значения переменной house1 переменной house2 просто заставляетпеременную house2 ссылаться на тот же объект, на который ссылается и переменнаяhouse1, В результате на этот объект можно воздействовать, используя либо имя house1,либо имя house2. Например, присвоивhouse1.area = 2600;мы добьемся того, что обе инструкцииConsole.WriteLine(house1.area);Console.WriteLine(house2.area);отобразят одно и то же значение — 2600.Несмотря на то что обе переменные, house1 и house2, ссылаются на один и тот жеобъект, они никак не связаны между собой. Например, очередное присвоение переменнойhouse2 просто заменяет объект, на который она ссылается. После выполненияпоследовательности инструкцийBuilding house1 = new Building();Building house2 = house1;Building house3 = new Building();Building house2 = house3;// Теперь переменные house2 и// house3 ссылаются на один и// тот же объект.переменная house2 будет ссылаться на тот же объект, на который ссылается переменнаяhouse3.