Главная страница
Навигация по странице:

  • Введение в классы

  • Общая форма определения класса

  • Определение класса

  • Создание объектов

  • Переменные ссылочного типа и присвоение им значений

  • Справочник по C# Герберт Шилдт ббк 32. 973. 26018 75 Ш57 удк 681 07 Издательский дом "Вильямс" Зав редакцией


    Скачать 5.05 Mb.
    НазваниеСправочник по C# Герберт Шилдт ббк 32. 973. 26018 75 Ш57 удк 681 07 Издательский дом "Вильямс" Зав редакцией
    АнкорC #.pdf
    Дата08.12.2017
    Размер5.05 Mb.
    Формат файлаpdf
    Имя файлаC #.pdf
    ТипСправочник
    #10795
    страница8 из 52
    1   ...   4   5   6   7   8   9   10   11   ...   52
    Глава 6
    Введение в классы,
    объекты и методы

    Глава 6. Введение в классы, объекты и методы
    127 этой главе вы познакомитесь с классом. В нем вся суть C#, поскольку именно классом определяется природа объекта. Это — фундамент, на котором построен язык C#.
    Класс как таковой формирует основу для объектно-ориентированного программирования в
    C#. Внутри класса определяются данные и код действий, выполняемых над этими данными.
    Этот код сосредоточен в методах. Получив представление о классах, объектах и методах, вы сможете писать более сложные программы и лучше понимать ключевые элементы C#, описанные в следующих главах.
    Введение в классы
    Поскольку все C#-программы оформляются в виде класса, мы работаем с классами с самого начала этой книги. Конечно же, мы использовали самые простые классы, с помощью которых нельзя продемонстрировать все их достоинства. Как будет показано ниже, классы
    — это очень мощный инструмент, и вы еще сумеете оценить их богатые возможности.
    Итак, начнем с азов. Класс — это шаблон, который определяет форму объекта. Он задает как данные, так и код, который оперирует этими данными. C# использует спецификацию класса для создания объекта. Объекты — это экземпляры класса. Таким образом, класс — это множество намерений (планов), определяющих, как должен быть построен объект. Важно четко понимать следующее: класс — это логическая абстракция. О ее реализации нет смысла говорить до тех пор, пока не создан объект класса, и в памяти не появилось физическое его представление.
    И еще. Вспомните, что методы и переменные, составляющие класс, называются
    членами класса.
    Общая форма определения класса
    Определяя класс, вы определяете данные, которые он содержит, и код, манипулирующий этими данными. Несмотря на то что очень простые классы могут включать только код или только данные, большинство реальных классов содержат и то, и другое.
    Данные содержатся в переменных экземпляров, определяемых классом, а код — в методах. Однако важно с самого начала отметить, что класс определяет также ряд специальных членов данных и методов-членов, например статические переменные, константы, конструкторы, деструкторы, индексаторы, события, операторы и свойства. Пока мы ограничимся рассмотрением переменных экземпляров и методов класса, а к концу главы познакомимся с конструкторами и деструкторами. Остальные типы членов класса описаны в последующих главах.
    Класс создается с помощью ключевого слова class
    . Общая форма определения класса, который содержит только переменные экземпляров и методы, имеет следующий вид: class
    имя_класса
    {
    //
    Объявление переменных экземпляров.
    доступ
    тип
    переменная1
    ;
    доступ
    тип
    переменная2
    ;
    //...
    доступ
    тип
    переменнаяN
    ;
    //
    Объявление методов.
    доступ
    тип_возврата
    метод1
    (
    параметры
    ) {
    // тело метода
    }
    В

    128
    Часть I. Язык C#
    доступ
    тип_возврата
    метод2
    (
    параметры
    ) {
    // тело метода
    }
    доступ
    тип_возврата
    методN
    (
    параметры
    ) {
    // тело метода
    }
    }
    Обратите внимание на то, что объявление каждой переменной и каждого метода предваряется элементом
    доступ
    . Здесь элемент
    доступ
    означает спецификатор доступа
    (например, public
    ), который определяет, как к этому члену можно получить доступ. Как упоминалось в главе 2, члены класса могут быть закрытыми в рамках класса или более доступными. Спецификатор доступа определяет, какой именно разрешен тип доступа.
    Спецификатор доступа необязателен, и, если он не указан, подразумевается, что этот член закрыт (
    private
    ). Члены с закрытым доступом (закрытые члены) могут использоваться только другими членами своего класса. В примерах этой главы все члены классов определяются как public
    -члены, а это значит, что их могут использовать все остальные составные части программного кода, даже те, которые определены вне класса. К рассмотрению спецификаторов доступа мы вернемся в главе 8.
    Несмотря на отсутствие специального синтаксического правила определения класса
    (его качественного и количественного состава), все же считается, что класс должен определять только одну логическую сущность. Например, класс, в котором хранятся имена лиц и их телефонные номера, не должен (по общепринятым меркам) также содержать информацию о среднем количестве осадков, циклах возникновения пятен на Солнце и прочую не связанную с конкретными лицами информацию. Другими словами, правильно определенный класс должен содержать логически связанные данные. И наоборот, помещая в один класс логически несвязанные данные, вы рискуете деструктурировать свой код.
    Классы, которые мы использовали в этой книге до сих пор, содержали только один метод —
    Main()
    . Вскоре мы узнаем, как создавать и другие методы. Однако заметьте, что в общей форме определения класса метод
    Main()
    не задан. Он нужен только в том случае, если определяемый класс является отправной точкой программы.
    Определение класса
    Для иллюстрации мы создадим класс, который инкапсулирует информацию о зданиях
    (домах, складских помещениях, офисах и пр.). В этом классе (назовем его
    Building
    ) будут храниться три элемента информации о зданиях (количество этажей, общая площадь и количество жильцов).
    Ниже представлена первая версия класса
    Building
    . В нем определены три переменные экземпляра: floors
    , area и occupants
    . Обратите внимание на то, что класс
    Building не содержит ни одного метода. Поэтому пока его можно считать классом данных. (В следующих разделах мы дополним его методами.) class Building { public int floors; // количество этажей public int area; // общая площадь основания здания public int occupants; // количество жильцов
    }
    Переменные экземпляра, определенные в классе
    Building
    , иллюстрируют общий способ их объявления. Формат объявления переменной экземпляра такой:
    доступ
    тип
    имя_переменной
    ;

    Глава 6. Введение в классы, объекты и методы
    129
    Здесь элемент
    доступ
    представляет спецификатор доступа, элемент
    тип
    — тип переменной экземпляра, а элемент
    имя_переменной
    — имя этой переменной. Таким образом, если не считать спецификатор доступа, то переменная экземпляра объявляется так же, как локальная переменная. В классе
    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;

    130
    Часть I. Язык C#
    //
    Вычисляем площадь, приходящуюся на одного жильца дома. 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;

    Глава 6. Введение в классы, объекты и методы
    131 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 приходится на одного человека

    132
    Часть I. Язык C#
    Как видите, данные о доме (содержащиеся в объекте house
    ) совершенно не связаны с данными об офисе (содержащимися в объекте office
    ). Эта ситуация отображена на рис.
    6.1.
    Рис. 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 связана с объектом.
    Тот факт, что к объектам классов доступ осуществляется посредством ссылок, объясняет, почему классы называются ссылочными типами. Ключевое различие между типами floors area occupants
    2 2500 4
    house floors area occupants
    3 4200 25
    office

    Глава 6. Введение в классы, объекты и методы
    133 значений и ссылочными типами состоит в значении, которое содержит переменная каждого типа. Переменная типа значения сама содержит значение. Например, после выполнения следующих инструкций 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
    . Объект, на который ссылается переменная house1
    , не меняется.

    1   ...   4   5   6   7   8   9   10   11   ...   52


    написать администратору сайта