Интернет-журнал "Домашняя лаборатория", 2007 №9
Шрифт:
Язык программирования должен позволять программисту в момент определения класса указать, к развернутому или ссылочному типу относится класс. К сожалению, язык C# не позволяет этого сделать напрямую — в нем у класса нет модификатора, позволяющего задать развернутый или ссылочный тип. Какие же средства языка позволяют частично решить эту важную задачу? В лекции 3, где рассматривалась система типов языка С#, отмечалось, что все типы языка делятся на ссылочные и значимые. Термин "значимый" является синонимом термина "развернутый". Беда только в том, что деление на значимые
Классы и структуры
Структура — это частный случай класса. Исторически структуры используются в языках программирования раньше классов. В языках PL/1, С и Pascal они представляли собой только совокупность данных (полей класса), но не включали ни методов, ни событий. В языке C++ возможности структур были существенно расширены и они стали настоящими классами, хотя и с некоторыми ограничениями. В языке C# — наследнике C++ — сохранен именно такой подход к структурам.
Чем следует руководствоваться, делая выбор между структурой и классом? Полагаю, можно пользоваться следующими правилами:
• если необходимо отнести класс к развернутому типу, делайте его структурой;
• если у класса число полей относительно невелико, а число возможных объектов относительно велико, делайте его структурой. В этом случае память объектам будет отводиться в стеке, не будут создаваться лишние ссылки, что позволит повысить эффективность работы;
• в остальных случаях проектируйте настоящие классы.
Поскольку на структуры накладываются дополнительные ограничения, то может возникнуть необходимость в компромиссе — согласиться с ограничениями и использовать структуру либо пожертвовать развернутостью и эффективностью и работать с настоящим классом. Стоит отметить: когда говорится, что все встроенные типы — int и другие — представляют собой классы, то, на самом деле, речь идет о классах, реализованных в виде структур.
Структуры
Рассмотрим теперь более подробно вопросы описания структур, их синтаксиса, семантики и тех особенностей, что отличают их от классов.
Синтаксис структур
Синтаксис объявления структуры аналогичен синтаксису объявления класса:
[атрибуты][модификаторы]struct имя_структуры[: список_интерфейсов]
{тело_структуры}
Какие изменения произошли в синтаксисе в сравнении с синтаксисом класса, описанным в лекции 16? Их немного. Перечислим их:
• ключевое слово class изменено на слово struct;
•
• для структур неприменимы модификаторы abstract и sealed. Причиной является отсутствие механизма наследования.
Все, что может быть вложено в тело класса, может быть вложено и в тело структуры, поля, методы, конструкторы и прочее, включая классы и интерфейсы.
Аналогично классу, структура может иметь статические и не статические поля и методы, может иметь несколько конструкторов, в том числе статические и закрытые конструкторы. Для структур можно создавать собственные константы, используя поля с атрибутом readonly и статический конструктор. Структуры похожи на классы по своему описанию и ведут себя сходным образом, хотя и имеют существенные различия в семантике присваивания.
Перечислим ограничения, накладываемые на структуры.
• Самое серьезное ограничение связано с ограничением наследования. У структуры не может быть наследников. У структуры не может быть задан родительский класс или родительская структура. Конечно, всякая структура, как и любой класс в С#, является наследником класса Object, наследуя все свойства и методы этого класса. Структура может быть наследником одного или нескольких интерфейсов, реализуя методы этих интерфейсов.
• Второе серьезное ограничение связано с процессом создания объектов. Пусть T — структура, и дано объявление без инициализации — T х. Это объявление корректно, в результате будет создан объект без явного вызова операции new. Сущности х будет отведена память, и на этой памяти будет развернут объект. Но поля объекта не будут инициализированы и, следовательно, не будут доступны для использования в вычислениях. Об этих особенностях подробно говорилось при рассмотрении значимых типов. В этом отношении все, что верно для типа int, верно и для всех структур.
• Если при объявлении класса его поля можно инициализировать, что найдет отражение при работе конструктора класса, то поля структуры не могут быть инициализированы.
• Конструктор по умолчанию у структур имеется, при его вызове поля инициализируются значениями по умолчанию. Этот конструктор нельзя заменить, создав собственный конструктор без аргументов.
• В конструкторе нельзя вызывать методы класса. Поля структуры должны быть проинициализированы до вызова методов.
Класс Rational или структура Rational