Рассмотрев интуитивное определение понятия класса, а также представив домены как формальную модель классов языков программирования в целом, остановимся более подробно на классах в языке объектно-ориентированного программирования C#.
По аналогии с другими известными языками объектно-ориентированного программирования (в частности, C++ и Java), под классом в языке C# понимается ни что иное, как ссылочный тип, определенный пользователем.
При этом для классов языка программирования C# допустимо только единичное наследование. В случае необходимости реализации множественного наследования возможно наследование посредством механизма интерфейсов, который будет подробнее рассмотрен далее в ходе курса.
Членами (или, иначе, элементами) класса языка программирования C# могут являться следующие конструкции:
константа, поле, метод, оператор, конструктор, деструктор;
свойство, индексатор, событие;
Доступ к членам класса определяется исходя из значения модификатора области действия идентификатора класса, который может принимать следующие значения: public, protected, private (данное значение используется по умолчанию), internal, protected internal.
Инициализация объекта класса языка программирования C# производится посредством оператора new, о котором будет рассказано ниже.
Рассмотрим манипулирование классами на примере следующих фрагментов программ на языке C#.
Прежде всего, приведем простейшее описание класса. Описание класса C c целочисленным полем value на языке C# имеет вид:
class C { ... int value = 0; ... }
Заметим, что в описании класса C на языке программирования C# кроме рассмотренного поля value могут присутствовать и другие поля (т.е. атрибуты объектов класса) допустимых в языке C# типов, а также методы (т.е. способы манипулирования объектами данного класса).
В языке программирования C# инициализация поля (т.е. связывание его с начальным значением) не является обязательной. Для обеспечения безопасности программного кода и в силу реализации принципа инкапсуляции, инициализация поля некоторого класса C не должна открывать возможностей для доступа к полям и методам данного типа.
При этом доступ к элементам класса внутри класса реализуется посредством обращения и не требует полного имени объекта:
... value ...
В отличие от предыдущего случая, доступ из сторонних классов требует указания полного имени объекта (в примере последовательно производятся инициализация и обращение):
C c = new C(); ... c.value ...
Рассмотрим более развернутый пример описания классов и манипулирования их элементами.
Приведем описание класса Rectangle, моделирующего прямоугольник с полями origin, width и height, моделирующими, соответственно, начальную точку (с парой координат), ширину и высоту, а также методом MoveTo, моделирующим перемещение начальной точки в заданную:
class Rectangle { Point origin; public int width, height; public Rectangle(){ origin = new Point(0,0); width=height=0; } public Rectangle ( Point p, int w, int h){ origin = p; width = w; height = h; } public void MoveTo (Point p) { origin = p; } }
Заметим, что модификатор области видимости для данного класса и его элементов разрешает общедоступное применение (public). Рассмотрим пример использования класса Rectangle:
Rectangle r = new Rectangle( new Point(10,20),5,5); int area = r.width * r.height; r.MoveTo(new Point(3,3));
Заметим, что в данном примере последовательно осуществляются инициализация объекта класса Rectangle с начальной точкой (10,20), шириной и высотой в пять единиц (т.е. квадрата), подсчет его площади area и перемещение начала отсчета в точку с координатами (3,3).
В результате анализа рассмотренных примеров становится очевидным, что объект является принципиально динамическим и изменяет состояние в зависимости от соотнесения (времени и внешних воздействий).
В этой связи исследуем более подробно простейший, статический случай полей объекта, который в языке программирования C# выделен в самостоятельный синтаксический элемент, характеризующийся независимостью от состояния объекта (и потому условно принадлежащий к классу). Приведем модифицированный пример предыдущего класса для случая статических полей:
class Rectangle { static Color defaultColor; // для каждого класса static readonly int scale; // для каждого класса int x, y, width,height; // для каждого объекта ... }
Заметим, что статические поля defaultColor и scale остаются неизменными внутри класса, тогда как динамические поля x, y, width и height индивидуально изменяются в зависимости от состояния каждого из объектов класса. Доступ изнутри класса осуществляется посредством обращения:
... defaultColor ... scale ...
а из внешних классов - посредством обращения:
... Rectangle.defaultColor ... Rectangle.scale ...
с указанием полных имен объектов. Поскольку статические поля являются неизменными со временем, они реализуются выделением памяти из статической области.