<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="http://man.deeptown.org/skins/common/feed.css?303"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://man.deeptown.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=KroTozeR</id>
		<title>Deeptown Manual - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://man.deeptown.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=KroTozeR"/>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/KroTozeR"/>
		<updated>2026-05-31T10:32:58Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.20.2</generator>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%9A%D0%BB%D0%B0%D1%81%D1%81%D1%8B_%D0%B8_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B</id>
		<title>Классы и объекты</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%9A%D0%BB%D0%B0%D1%81%D1%81%D1%8B_%D0%B8_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B"/>
				<updated>2007-10-05T11:38:46Z</updated>
		
		<summary type="html">&lt;p&gt;KroTozeR: /* Расширения */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== История развития ООП ==&lt;br /&gt;
&lt;br /&gt;
Для того чтобы понять, что же такое классы и объекты, сперва необходимо проследить историю развития программирования. А конкретнее, историю возникновения концепции ООП. Автор верит, что знание истории возникновения тех или иных мыслей и идей может помочь читателю осознать необходимость нововведений, и главное — их преимуществ перед существовавшими в то время решениями.&lt;br /&gt;
&lt;br /&gt;
=== Возникновение языков программирования ===&lt;br /&gt;
&lt;br /&gt;
На заре зарождения вычислительных машин их приходилось программировать поистине &amp;quot;вручную&amp;quot;. Все, что было в руках  программиста это пульт управления ЭВМ. На шестнадцатеричной клавиатуре (а еще раньше на пульте с тумблерами) программист задавал некоторый адрес ячейки памяти, затем он мог либо выполнить операцию чтения — тогда на табло появлялись цифры, соответствующие значению ячейки памяти, либо операцию записи — при этом, по указанному адресу записывалось значение, набранное на клавиатуре данных. Затем, программист переходил к следующей ячейке, и так повторялось до тех пор, пока в память ЭВМ не была внесена вся программа. На программистах (точнее, на операторах ЭВМ) лежала огромная ответственность! Одна ошибка, один неверно установленный переключатель или одна пропущенная команда неминуемо вели к ошибкам в работе программы, а, следовательно, и к ошибкам в расчетах. Могли потребоваться недели, и даже месяцы на поиск этой ошибки и на ее исправление! Естественно, ни о каких языках программирования тогда не могло идти и речи.&lt;br /&gt;
&lt;br /&gt;
=== Появление ассемблера ===&lt;br /&gt;
&lt;br /&gt;
Впоследствии, программисты смекнули, что команды можно записывать в виде мнемонических обозначений или мнемоник — то, что раньше применялось только для удобства записи на бумаге — было стандартизировано и приспособлено как ''язык'' общения человека и ЭВМ. Так появился первый язык программирования — ''язык ассемблера''. Конечно, языком его можно назвать с некоторой натяжкой, ведь он не обеспечивал и десятой доли тех возможностей (вроде автоматического разбора арифметических выражений), которые мы привыкли ассоциировать с языками программирования. Тем не менее, ассемблер выполнял свою главную и основную функцию — избавлял программиста от необходимости работать с памятью (и адресами) напрямую. Вместо этого, программист записывал свои команды в стандартной форме, понятной ЭВМ. Далее выполнялась программа ''транслятор'', которая преобразовывала исходный текст программы в поток машинных команд, которые уже можно исполнять.&lt;br /&gt;
&lt;br /&gt;
=== Концепция языка высокого уровня ===&lt;br /&gt;
&lt;br /&gt;
...С увеличением сложности программ, программировать на ассемблере становилось все сложнее и сложнее.  Ввиду естественных ограничений человеческой памяти и внимания, написание программ и их отладка стали настолько сложными, что люди всерьез подошли к рассмотрению идеи языка высокого уровня — некоторой системы обозначений и абстрактных команд, которая позволила бы записывать программы в абстрактной форме, не заботясь о том, как располагать в памяти код и данные, как их структурировать и т. д. Всю эту работу брал на себя компилятор. Кроме того, он обеспечивал программиста удобным способом записи математических выражений — в естественной форме. При этом, компилятор сам &amp;quot;разворачивал&amp;quot; эти выражения в наборы инструкций ассемблера, попутно подставляя значения констант и адреса переменных. Это дало возможность программистам записывать формулы вычислений в натуральном виде, что уменьшало трудозатраты, ускоряло написание программ и уменьшало вероятность ошибок. Тем не менее, многие авторитеты того времени очень негативно отзывались о языках высокого уровня. В то время языки были довольно несовершенными и генерировали &amp;quot;ужасный&amp;quot; с точки зрения программистов код. Код был не оптимален, занимал огромное по тем временам количество памяти и работал медленнее, чем та же программа, написанная на ассемблере. Смешно сказать, но в то время многие не верили в то, что будущее за ЯП высокого уровня; их считали не более чем игрушкой для &amp;quot;чайников&amp;quot;, возжелавших вообразить себя настоящими программистами. &lt;br /&gt;
&lt;br /&gt;
Но время шло, количество приверженцев нового подхода постоянно увеличивалось. Сами же компиляторы становились все более мощными и генерировали все более компактный и оптимальный код. Дошло до того, что компилятор с оптимизатором в некоторых случаях генерировал код, более качественный, чем это делал программист. С этого момента ЯП высокого уровня заняли свое место в истории и в инструментарии любого разработчика.&lt;br /&gt;
&lt;br /&gt;
=== Структурное программирование ===&lt;br /&gt;
&lt;br /&gt;
С развитием языков программирования появились новые концепции и новые парадигмы программирования. От линейного моноблочного программирования, при котором программа писалась единым &amp;quot;куском&amp;quot; от начала до конца, перешли к программам модульным и структурным. При них программа представляла уже совокупность процедур (функций), которые вызывали друг друга в ходе работы программы. Процедуры представляли собой подпрограммы, решающие отдельные частные задачи. При этом код получался более читаемым, и облегчалась его отладка. &lt;br /&gt;
&lt;br /&gt;
Опять же, в ходе усложнения решаемых задач и, вследствие этого, увеличения количества переменных с которыми приходилось работать программисту, возникла идея группировки некоторых переменных в группы или структуры. Структуры формировались по назначению и содержали в себе переменные, имеющие отношение к одной и той же сущности. Это значительно повысило читаемость программ и уменьшило количество ошибок в них.&lt;br /&gt;
&lt;br /&gt;
=== Объектно-ориентированное программирование ===&lt;br /&gt;
&lt;br /&gt;
Ну и наконец, одна светлая голова додумалась до мысли: &amp;quot;а что если в структурах группировать не только переменные, но и сами процедуры которые должны работать с этими переменными?&amp;quot;. В результате получилось то, что мы сейчас называем классом — то есть, некоторая обособленная функциональная сущность, которая сама хранит свои данные, а главное сама умеет их обрабатывать. Теперь программисту не нужно помнить, какая из процедур отвечает за некоторое действие над такими-то переменными — он просто берет объект и работает с ним. Все что происходит с объектом внутри — это его личное дело.&lt;br /&gt;
&lt;br /&gt;
Последним шагом к современному пониманию программ явились концепции [http://ru.wikipedia.org/wiki/Полиморфизм_(программирование) полиморфизма], [http://ru.wikipedia.org/wiki/Инкапсуляция_(программирование) инкапсуляции] и [http://ru.wikipedia.org/wiki/Наследование_(программирование) наследования]. Не будем пока углубляться в суть этих понятий, отметим только, что их введение сформировало современное понимание объектно-ориентированного программирования.&lt;br /&gt;
&lt;br /&gt;
При написании программы на объектно-ориентированном языке, программист строит математическую модель взаимодействия различных сущностей. Каждая из сущностей это свой мир, у которого есть свои законы и особенности. При этом сущности могут быть как конкретные, вроде &amp;quot;сетевой интерфейс&amp;quot; или &amp;quot;файл&amp;quot;, так и совершенно абстрактные, например &amp;quot;отношение&amp;quot; или &amp;quot;ошибка&amp;quot;. Программист описывает каждую из сущностей в отдельности, обособлено от остальных. Вся необходимая для работы информация хранится внутри, а для взаимодействия с внешним миром предусмотрен ''интерфейс'' — некоторая совокупность ''свойств'' данной сущности (отражающих ее внутреннее состояние) и способов взаимодействия с ней — ''методов''.&lt;br /&gt;
&lt;br /&gt;
В ходе работы программы сущности могут взаимодействовать, читая и записывая свойства и вызывая методы друг друга, использовать друг друга как подсистемы, порождать новые сущности и т. д. Получается, что при написании программы, программист переносит свое внутреннее представление того как он видит эту программу, то из чего она состоит и как отдельные ее части взаимодействуют. Теперь не приходится адаптировать свое понимание проблемы к конкретным инструментальным средствам и возможностям языка программирования (конечно, это все же происходит, но уже гораздо менее заметно).&lt;br /&gt;
&lt;br /&gt;
В терминах современных языков программирования такие сущности называются ''классами'', в смысле ''классами сущностей''. А отдельные представители этих классов называются ''экземплярами'', ''инстанциями'' (на английский манер) или ''объектами''. Более подробно, различие между классами и объектами будет рассмотрено ниже.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Итак, любой современный объектно-ориентированный язык оперирует понятиями классов и объектов. Точно такой же подход нашел свое применение в нашей виртуальной машине. Основой всей платформы Gide является объектно-ориентированный принцип. Причем, в этом смысле она является более объектно-ориентированной, нежели традиционные ЯП вроде C++. В C++ существуют понятия элементарных типов. Это сделано в целях производительности и было продиктовано архитектурой самого языка. В классических языках программирования, элементарные типы, так или иначе, отражают сущности из &amp;quot;реального мира&amp;quot;. Например, целочисленные типы int и short соответствуют 32х и 16ти разрядным регистрам процессора, указатели и строки соответствуют представлению данных в памяти и т. д. В Gide это не так. Все с чем оперирует виртуальная машина — это объекты. Соответственно, не существует понятия элементарных типов (просто нет критерия, который бы позволил отделить одно от другого). &lt;br /&gt;
&lt;br /&gt;
Язык K++ в полной мере наследует идеологию Gide. Скажем, для него нет отличия между типом &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt; (целое число) и некоторым пользовательским классом &amp;lt;tt&amp;gt;MyWeirdClass&amp;lt;/tt&amp;gt;: везде, где можно использовать &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;, можно использовать &amp;lt;tt&amp;gt;MyWeirdClass&amp;lt;/tt&amp;gt; и наоборот. Более того, это позволяет работать с системными классами так же, как с пользовательскими! Например, ничто не мешает унаследовать свой класс от класса &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;, равно как ничто не мешает определить математические операторы для класса &amp;lt;tt&amp;gt;MyWeirdClass&amp;lt;/tt&amp;gt; и использовать объекты этого класса в арифметических выражениях. При этом изменится логика работы всего языка. К примеру, после добавления некоторого метода к классу int можно будет вызывать методы у всех его экземпляров, даже тех, что представлены числовыми константами внутри самого языка!&lt;br /&gt;
&lt;br /&gt;
== Понятие класса ==&lt;br /&gt;
&lt;br /&gt;
Что такое ''класс'' проще всего объяснить на примерах. Представьте, что вас спрашивают &amp;quot;что такое яблоко?&amp;quot;. Скорее всего, вы ответите что-то вроде: &amp;quot;яблоки, это вкусные плоды, растущие на деревьях — яблонях; они бывают разных цветов и размеров&amp;quot;. Заметьте, что когда мы описываем ''яблоки как понятие'', мы не имеем в виду некоторый конкретный объект, а скорее описываем наше обобщенное представление о них. Если же вас попросят описать совершенно конкретное яблоко, лежащее на блюдечке перед вами, вы будете говорить о нем по другому: &amp;quot;это яблоко, оно красное, сочное, судя по всему спелое. С черенком, на котором остался листик, и маленькой червоточинкой&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Разница заключается в том, что когда вы говорили ''о яблоках'', вы описывали свое представление яблок, как ''класса'' объектов. Когда вы описывали ''яблоко'', то вы имели в виду конкретный ''экземпляр'', или ''объект''. Говоря о классе, вы можете описать только те свойства, что принадлежат всем яблокам; когда же вы описываете объект, то в первую очередь имеете в виду его индивидуальные особенности (свойства). Тем не менее, описание объекта начинается с упоминания его класса (&amp;quot;это яблоко,...&amp;quot;), а затем уже свойств объекта (ведь &amp;quot;сочным и спелым&amp;quot; может быть и апельсин). Это важная особенность объектно-ориентированного подхода. &lt;br /&gt;
&lt;br /&gt;
Другой пример: если вас попросить &amp;quot;представьте дерево&amp;quot;, то вы либо представите некоторое совершенно абстрактное, усредненное дерево, либо попросите уточнить, какое именно дерево имеется в виду. Ваше сознание из имеющейся информации смогло уяснить только самые общие сведения о классе. Но этой информации не достаточно, для более детального описания. Это тоже важно, поскольку в этом простом примере кроется сущность механизма наследования — постепенного уточнения классами-потомками общих черт своих предков. Таким образом, и яблоня, и груша — деревья. Но яблони отличаются от груш. Получается, что классы ''яблони'' и ''груши'' имеют общего предка — класс ''дерево''.&lt;br /&gt;
&lt;br /&gt;
Таким образом, понятия классов и объектов это не математическая абстракция, а скорее часть нашего восприятия мира, того как мы мыслим.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из примеров выше мы смогли уяснить следующее:&lt;br /&gt;
&lt;br /&gt;
* Классы, это некоторые абстрактные сущности, задающие общие черты своих объектов&lt;br /&gt;
* Все объекты одного класса похожи друг на друга, но имеют некоторые индивидуальные особенности&lt;br /&gt;
* Классы могут наследоваться, расширяя набор свойств класса родителя своими собственными&lt;br /&gt;
&lt;br /&gt;
Перейдем теперь ближе к основной теме нашего повествования, а именно языку К++:&lt;br /&gt;
&lt;br /&gt;
С точки зрения языка, ''класс'' представляет собой набор следующих элементов:&lt;br /&gt;
* ''полей'', т.е. переменных, хранящих индивидуальные особенности объектов, &lt;br /&gt;
* ''методов'', т.е. функций, определяющих поведение данного объекта;&lt;br /&gt;
* ''свойств'', определяющих взаимодействие других объектов с объектами данного класса.&lt;br /&gt;
&lt;br /&gt;
''Поля'' — это переменные, которые относятся к некоторому конкретному экземпляру нашего класса. Каждый экземпляр имеет свою копию набора переменных, таким образом, они могут хранить свое состояние (например, показатель &amp;quot;спелости&amp;quot;, в примере с яблоками). Эти переменные доступны только самому классу, доступ извне для них запрещен. Для того чтобы частично разрешить этот доступ, применяются ''свойства''. Сами свойства будут описаны позже, здесь стоит отметить только то, что свойство может быть доступно &amp;quot;только на чтение&amp;quot;, &amp;quot;только на запись&amp;quot; или &amp;quot;и на чтение и на запись&amp;quot;. Свойство может быть связано либо с некоторым полем, либо с методом. Например, если свойство доступно &amp;quot;только на чтение&amp;quot; то его можно использовать для получения значения, но не для его записи (то есть, такое свойство не может фигурировать в качестве [[lvalue]]).&lt;br /&gt;
&lt;br /&gt;
''Методы'' — это тот самый, связанный с данными код (вспомните [[Классы и объекты#История развития ООП|историю ООП]]) который, естественно, может работать с переменными объекта (то есть с полями) и служит для описания поведения данного класса объектов.&lt;br /&gt;
&lt;br /&gt;
Класс может иметь одного или нескольких родителей (опять же, подробнее об этом см. ниже)&lt;br /&gt;
&lt;br /&gt;
Методы и свойства класса могут находиться в различных областях видимости. Это обеспечивается с помощью [[Спецификаторы доступа|спецификаторов доступа]]:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''private'''&amp;lt;/tt&amp;gt; — Частная собственность! Видимость только внутри методов данного класса&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''protected'''&amp;lt;/tt&amp;gt; — &amp;quot;Семейная реликвия&amp;quot;, доступ внутри методов данного класса и всех его дочерних классов&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''public'''&amp;lt;/tt&amp;gt; — видимость и доступ для всех&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' По умолчанию методы имеют видимость &amp;lt;tt&amp;gt;'''private'''&amp;lt;/tt&amp;gt;, в то время как свойства — &amp;lt;tt&amp;gt;'''public'''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Приведем, наконец, пример объявления класса:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
class MyWeirdClass {&lt;br /&gt;
    var m_x = 0;  // поле m_x, изначально проинициализированное нулем&lt;br /&gt;
    const m_y = 1; // поле-константа m_y&lt;br /&gt;
&lt;br /&gt;
    // методы класса&lt;br /&gt;
    public const function int get_mul() { return m_x * m_y; }&lt;br /&gt;
    public function void set_mul(int x) { m_x = x / m_y; }&lt;br /&gt;
&lt;br /&gt;
    // свойство класса&lt;br /&gt;
    public property mul read get_mul write set_mul;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;1: Как у любого нормального разумного существа, у класса есть &amp;quot;голова&amp;quot; и &amp;quot;тело&amp;quot;. Ключевое слово &amp;lt;tt&amp;gt;'''class'''&amp;lt;/tt&amp;gt; начинает объявление класса. Далее за ним следует [[идентификатор]] имени класса, после чего идет тело класса.&lt;br /&gt;
&lt;br /&gt;
;3-4: Здесь мы видим объявление двух полей класса — переменной ''m_x'' и константы ''m_y'', которые, подобно обычным переменным инициализируются тут же, на месте объявления (камень в огород C++). Зачем нужны поля-константы, описано в главе [[Константы]].  &lt;br /&gt;
&lt;br /&gt;
;7-8: Для доступа к состоянию объекта, определены два метода: ''аксессор'' &amp;lt;tt&amp;gt;get_mul()&amp;lt;/tt&amp;gt; и ''мутатор'' &amp;lt;tt&amp;gt;set_mul()&amp;lt;/tt&amp;gt;. Подобные конструкции применяются настолько часто, что им были даны специальные имена. Как видно из названия, первый метод дает доступ к значению, второй изменяет или мутирует его.&lt;br /&gt;
&lt;br /&gt;
;11: Завершается объявление класса объявлением свойства ''mul'', которое связывается с аксессором и мутатором. Думаю, читатель уже догадался, что это свойство типа &amp;quot;чтение и запись&amp;quot;. Таким образом, при обращении к свойству на чтение, будет вызван аксессор, а результат его выполнения будет возвращен в качестве значения свойства. И, наоборот, при попытке записать в свойство некоторое значение, будет вызван мутатор, в качестве аргумента которому будет передано это самое значение, а уж сам мутатор позаботится о том, чтобы оно было &amp;quot;доставлено по адресу&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
: '''Примечание:''' Зачем нужны такие сложности, и зачем дублировать вроде бы одинаковый функционал, будет описано ниже.&lt;br /&gt;
&lt;br /&gt;
== Понятие объекта ==&lt;br /&gt;
&lt;br /&gt;
Собственно, понятие объекта уже много раз было затронуто выше по повествованию. Поэтому здесь приведем лишь небольшое определение: Под ''объектом'' подразумевается экземпляр того или иного класса, т.е. некоторая сущность, поведение которой задается соответствующим классом.&lt;br /&gt;
&lt;br /&gt;
Для создания объекта того или иного класса служит оператор &amp;lt;tt&amp;gt;'''new'''&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
    var myWeirdObject = new MyWeirdClass;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь мы видим типичную конструкцию объявления переменной, однако в инициализаторе переменной находится всего один оператор, за которым следует [[идентификатор]] имени класса, экземпляр которого мы хотим создать.&lt;br /&gt;
&lt;br /&gt;
== Наследование ==&lt;br /&gt;
&lt;br /&gt;
Под ''наследованием'' классов понимается механизм такого создания (объявления) класса, при котором он расширяет функционал одного или нескольких уже существующих классов (родителей). Вспомните пример с деревьями. Когда мы говорим, что класс ''яблоня'' наследуется от класса ''дерево'' — это значит что ''яблоня'' унаследует все свойства своего класса-родителя, некоторые из которых он может изменить, ну и дополнить своими собственными свойствами. Опыт нам подсказывает, что у любого дерева есть листья (для простоты не будем вспоминать про хвойные), однако не любое дерево плодоносит яблоками. Если же рассмотреть сами яблоки, то можно сказать, что класс ''яблоко'' унаследован от класса ''фрукт'', который определяет что фрукты (и соответственно яблоки) должны расти на деревьях.&lt;br /&gt;
&lt;br /&gt;
Таким образом, наследование гарантирует, что к дочерним классам применимы все операции, доступные в родительском классе: любой алгоритм, работающий с объектами родительского класса, может работать с объектами его дочерних классов. &lt;br /&gt;
&lt;br /&gt;
Для задания наследования, в объявлении класса следует указать ключевое слово &amp;lt;tt&amp;gt;'''extends'''&amp;lt;/tt&amp;gt;,  за которым необходимо перечислить список идентификаторов классов-родителей, разделяя их запятыми:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
// коробка&lt;br /&gt;
class Box { &lt;br /&gt;
    // из чего сделана коробка?&lt;br /&gt;
    public const function string material() { return &amp;quot;Картон&amp;quot;; }&lt;br /&gt;
&lt;br /&gt;
    // что в коробке?&lt;br /&gt;
    public const function string contents() { return &amp;quot;Пусто&amp;quot;; }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// коробка с картошкой&lt;br /&gt;
class BoxWithPotatoes extends Box { &lt;br /&gt;
    public const function string contents() { return &amp;quot;Картошка&amp;quot;; }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function OutputBox(const Box b) {&lt;br /&gt;
    STDOUT.print(&amp;quot;Материал: &amp;quot; + b.material() + &amp;quot;, содержит: &amp;quot; + b.contents() + &amp;quot;\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function main() {&lt;br /&gt;
    var b1 = new Box;&lt;br /&gt;
    var b2 = new BoxWithPotatoes;&lt;br /&gt;
    OutputBox(b1); // Материал: Картон, содержит: Пусто&lt;br /&gt;
    OutputBox(b2); // Материал: Картон, содержит: Картошка&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;2-7: В этом примере мы создаем класс &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt;, который представляет собой некоторую коробку. Мы определяем ее свойства, такие как ''материал'' и ''содержимое''.&lt;br /&gt;
&lt;br /&gt;
;10-12: Далее мы определяем класс &amp;lt;tt&amp;gt;BoxWithPotatoes&amp;lt;/tt&amp;gt; (''коробка с картошкой''), который наследуется от класса &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt;, и тем самым заимствует свойства материала и содержимого, но первое он переопределяет (в случае методов это называется ''перекрытием'') собственным методом.&lt;br /&gt;
&lt;br /&gt;
;14-16: Мы определяем некоторую [[Функции|функцию]] для работы с нашими классами, которая будет отображать их состояние. Заметьте, что в качестве [[Функции#Аргументы|аргумента функции]] передается экземпляр класса &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt;, то есть класса-родителя. При этом мы предполагаем, что любой класс, унаследованный от базового класса, будет обладать необходимым нам интерфейсом, а именно методами получения информации о свойствах (аксессорами мы их не называем, потому что они не связаны с конкретным полем; это было бы неверно).&lt;br /&gt;
&lt;br /&gt;
;18-23: Объявляется функция &amp;lt;tt&amp;gt;main()&amp;lt;/tt&amp;gt;, внутри которой и происходит самое интересное. Сначала мы создаем два экземпляра ''b1'' и ''b2'' классов &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt; и &amp;lt;tt&amp;gt;BoxWithPotatoes&amp;lt;/tt&amp;gt; соответственно. А затем, вызываем вышеописанную функцию &amp;lt;tt&amp;gt;OutputBox()&amp;lt;/tt&amp;gt;, которая отображает содержимое. Вывод в терминал (написан в комментарии к вызову) показывает, как это все работает.&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' при использовании множественного наследования существует одно серьезное ограничение: его нельзя применять для наследования от классов стандартной библиотеки. Это ограничение связано с архитектурой платформы Gide. Однако его можно обойти с помощью создания [[Класс-обертка|классов-оберток]] для системного класса, с последующим наследованием от него нового класса.&lt;br /&gt;
&lt;br /&gt;
== Методы ==&lt;br /&gt;
&lt;br /&gt;
''Метод'' — это некоторый код, связанный с объектом и управляющий его поведением. Управление может заключаться в изменении переменных состояния объекта (полей), либо выполнением некоторых операций над ними.&lt;br /&gt;
&lt;br /&gt;
При объявлении метода могут быть указаны следующие ключевые слова, в указанном порядке:&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''private'''&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;'''protected'''&amp;lt;/tt&amp;gt; или &amp;lt;tt&amp;gt;'''public'''&amp;lt;/tt&amp;gt; — определяют область видимости метода&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''static'''&amp;lt;/tt&amp;gt; — указывает, что метод является ''статическим'' (см. ниже)&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''const'''&amp;lt;/tt&amp;gt; — метод не изменяет объект&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''function'''&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;'''operator'''&amp;lt;/tt&amp;gt; или &amp;lt;tt&amp;gt;'''constructor'''&amp;lt;/tt&amp;gt; указывает, что объявляется: ''метод'', ''[[Операторы|оператор]]'' или ''конструктор'' (см. ниже)&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''const'''&amp;lt;/tt&amp;gt; — метод возвращает результат, который нельзя изменять&lt;br /&gt;
&lt;br /&gt;
После этого указывается тип, возвращаемый методом. Если он опущен — возвращается [[Переменные#Нетипированные (динамические) переменные|динамическая переменная]]; если вместо типа указано ключевое слово &amp;lt;tt&amp;gt;'''void'''&amp;lt;/tt&amp;gt; — метод не возвращает результата. Следом за типом идет имя метода, затем — перечисление [[Функции#Аргументы|аргументов]] в скобках. Подробнее об объявлении функций и передаче параметров, можно прочитать в главе [[Функции]].&lt;br /&gt;
&lt;br /&gt;
Тело метода может быть объявлено как непосредственно в теле класса, так и вынесено за его пределы, например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
class MyClass {&lt;br /&gt;
    public const function string F1() { return &amp;quot;smth&amp;quot;; }&lt;br /&gt;
    public const function string F2();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function string MyClass::F2() {&lt;br /&gt;
    return F1();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;6: При вынесении функции за пределы класса, имя соответствующего метода предваряется именем класса, из которого он был вынесен; имена отделяются друг от друга символом &amp;quot;двойное двоеточие&amp;quot; ( &amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt; ); дополнительно — в заголовке вынесенной функции необходимо указать тип возвращаемого значения и параметры функции, все остальные ключевые слова указывать не обязательно.&lt;br /&gt;
&lt;br /&gt;
;7: В теле метода доступны все поля, методы и свойства данного класса и его предков. Например, в коде приведенном выше, метод &amp;lt;tt&amp;gt;F2()&amp;lt;/tt&amp;gt; вызывает метод &amp;lt;tt&amp;gt;F1()&amp;lt;/tt&amp;gt; для того же объекта.&lt;br /&gt;
&lt;br /&gt;
=== Статические методы ===&lt;br /&gt;
&lt;br /&gt;
''Статический метод класса'' — это метод, относящийся к данному классу, но не объекту этого класса. Т.е. это некоторая вспомогательная для данного класса функция.&lt;br /&gt;
&lt;br /&gt;
При объявлении статического метода нужно указать ключевое слово &amp;lt;tt&amp;gt;'''static'''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В теле статического метода нет возможности напрямую обращаться к другим методам данного класса, т.к. статическому методу недоступен объект класса. Фактически, единственным отличием статического метода от обычной функции является то, что такой метод может обращаться к защищенным полям и методам класса некоторого другого объекта. Подобный подход широко применяется при написании ''конструкторов'' (см. ниже).&lt;br /&gt;
&lt;br /&gt;
Пример:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
class MyClass {&lt;br /&gt;
    public static function string Info() { return &amp;quot;Я MyClass!&amp;quot;; }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function f() {&lt;br /&gt;
    // Вызов статического метода:&lt;br /&gt;
    var myClassInfo = MyClass.Info();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Конструкторы ===&lt;br /&gt;
&lt;br /&gt;
В ходе написания программы часто приходится создавать новые объекты. При этом объекту требуется установить некоторое начальное состояние. Разумеется, это выполняется либо путем написания инициализаторов соответствующих полей, либо значения полям присваиваются явным образом. Но что делать, если объект может иметь несколько начальных состояний? То есть, в зависимости от некоторых условий, одним и тем же полям объекта могут быть присвоены различные наборы значений. Тут уже одними инициализаторами не обойтись. Присваивать значения можно прямо в коде программы, однако это не очень красивое решение, поскольку один и тот же объект может создаваться в нескольких местах программы и придется копировать один и тот же участок кода, инициализирующий поля объекта. Недостаток этого подхода в том, что при большом количестве полей, программист может забыть проинициализировать некаторе поле, либо при изменении условий инициализации он может изменить их только в одном месте программы, забыв, что объект может создаваться и в других местах. Более разумным является подход, при котором программист пишет функцию, инициализирующую поля объекта. При этом весь код собирается в одном месте и вероятность ошибок значительно понижается. &lt;br /&gt;
&lt;br /&gt;
Конструкторы развивают эту идею, дополняя код инициализации полей кодом создания самого экземпляра объекта. То есть, в конструкторе собирается весь код, относящийся к созданию инстанции класса. Итак, ''конструктор класса'' — это специальный метод, инициализирующий объект класса. С точки зрения языка, конструктор — это статический метод класса, возвращающий экземпляр данного класса.&lt;br /&gt;
&lt;br /&gt;
Таким образом, следующие объявления в рамках класса эквивалентны:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
public constructor Create();&lt;br /&gt;
public static MyClass Create();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тело конструктора чаще всего выглядит следующим образом: сначала создается экземпляр класса при помощи оператора &amp;lt;tt&amp;gt;'''new'''&amp;lt;/tt&amp;gt;, затем производятся некоторые действия, инициализующие этот объект, и, наконец, этот объект возвращается в качестве результата. &lt;br /&gt;
&lt;br /&gt;
В качестве примера приведем пример реализации некоторого абстрактного класса &amp;lt;tt&amp;gt;MyStream&amp;lt;/tt&amp;gt;, использующего системную реализацию класса &amp;lt;tt&amp;gt;stream&amp;lt;/tt&amp;gt;, и определяющую собственный конструктор:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
class MyStream {&lt;br /&gt;
    var string m_URL;&lt;br /&gt;
    var stream m_Stream;&lt;br /&gt;
public:&lt;br /&gt;
    static const MODE_READ = 1;&lt;br /&gt;
    static const MODE_WRITE = 2;&lt;br /&gt;
    constructor open(const string url, int mode) {&lt;br /&gt;
        var self = new MyStream;&lt;br /&gt;
        self.m_Stream.open(url, mode);&lt;br /&gt;
        self.m_URL = url;&lt;br /&gt;
        return self;&lt;br /&gt;
    }&lt;br /&gt;
    // прочие методы (опущены для краткости)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;2-3: Объявляются поля ''m_URL'' и ''m_Stream'' нашего класса, которые будут инициализироваться в конструкторе. &lt;br /&gt;
&lt;br /&gt;
;5-6: В публичной области класса объявляются статические константы ''MODE_READ'' и ''MODE_WRITE'', которые задают желаемый режим доступа к открываемому потоку. Это единственный случай, когда поле класса доступно на прямой доступ извне.&lt;br /&gt;
&lt;br /&gt;
;7: Объявляется конструктор &amp;lt;tt&amp;gt;open()&amp;lt;/tt&amp;gt;, принимающий в качестве параметров [[URL]] ресурса который требуется открыть и число, задающее с помощью вышеописанных констант режим доступа к потоку. В теле конструктора мы создаем инстанцию ''self'' нашего класса. Затем производится попытка открытия потока ''m_Stream'': если операция пройдет успешно, то происходит инициализация оставшегося поля ''m_URL'' и выход из конструктора с возвратом созданной инстанции; если же операция открытия потока провалится, то будет сгенерировано ''[[Обработка исключений|исключение]]'' и выполнение конструктора прекратится (управление будет передано &amp;quot;наверх&amp;quot;, вызывающему коду).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Использовать наш класс можно примерно так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;var data = MyStream.open(&amp;quot;http://www.deeptown.org/index.html&amp;quot;, MyStream.MODE_READ);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на второй параметр функции, где мы передаем константу ''MODE_READ'', объявленную внутри самого класса. Подобный подход, когда константы, используемые при работе с классом, инкапсулируются в тело класса, помогает сконцентрировать код в одном месте и избежать многих ошибок. В результате повышается читаемость кода и не возникает конфликта имен констант.&lt;br /&gt;
&lt;br /&gt;
== Поля ==&lt;br /&gt;
&lt;br /&gt;
Поле класса — это некоторый объект, используемый объектом данного класса.&lt;br /&gt;
&lt;br /&gt;
Объявление поля начинается с одного из трех ключевых слов:&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''var'''&amp;lt;/tt&amp;gt;  — объявление &amp;quot;обычного&amp;quot; поля;&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''const'''&amp;lt;/tt&amp;gt; — данное поле является константой и не может быть изменено;&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''mutable'''&amp;lt;/tt&amp;gt; — значение данного поля не влияет на состояние объекта, и его можно менять даже в методах, объявленных константными.&lt;br /&gt;
&lt;br /&gt;
За ключевым словом следует тип поля и [[идентификатор]] его имени. Тип поля может быть опущен. После имени может стоять символ &amp;quot;=&amp;quot; и выражение, инициализирующее значение данного поля. В целом, синтаксис тот же, что и при объявлении обычной переменой или константы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var int m_x;&lt;br /&gt;
const m_y = 0;&lt;br /&gt;
var m_stream = new stream;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тип поля определяется по следующим правилам:&lt;br /&gt;
* если тип указан явно, ничего определять не надо;&lt;br /&gt;
* если тип не указан, но при объявлении использован инициализатор — типом становится тип результата инициализатора;&lt;br /&gt;
* в противном случае, для поля устанавливается [[Переменные#Нетипированные (динамические) переменные|динамический тип]].&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' В K++ доступ к полям имеет только объект класса — т.е. фактически, все поля находятся в закрытой (private) области видимости. Для предоставления внешним классам доступа к полям следует использовать ''свойства'' (см. ниже).&lt;br /&gt;
&lt;br /&gt;
== Свойства ==&lt;br /&gt;
&lt;br /&gt;
''Свойства'' — это специальные конструкции языка К++, которые позволяют совмещать обращение к данным с вызовом определенного метода. Смысл свойств заключается в том, чтобы программист мог контролировать процесс изменения состояния объекта и своевременно реагировать на это изменение. Свойства бывают доступны на чтение, на запись, или на чтение и на запись одновременно. Это связано с тем, что некоторые свойства объекта (в естественном понимании этого слова), могут предполагать только получение информации о них, другие же могут подразумевать изменение состояния, без возможности чтения. &lt;br /&gt;
&lt;br /&gt;
В существующих языках программирования, таких как C++ тот же функционал реализуется с помощью вызова специальных методов: ''аксессоров'' и ''мутаторов'', которые используются для получения сведений о некотором свойстве или для записи соответственно. Однако это делает код менее читаемым, особенно в случае мутаторов. Свойства же, позволяют работать с собой подобно обычным полям или объектам, используя операторы. &lt;br /&gt;
&lt;br /&gt;
Приведем два примера, которые позволят понять смысл свойств и их отличие от обычных полей класса.&lt;br /&gt;
&lt;br /&gt;
Предположим, что у нас есть класс, отвечающий за чтение состояния некоторого устройства. Допустим, состояние представляется целым числом и должно определяться по мере обращения. Если бы мы писали на языке C++, то мы оформили бы это в виде метода:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
class MyDevice {&lt;br /&gt;
    int GetState();&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Везде, где нам потребовалось бы читать состояние устройства мы должны были писать что-то типа:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int current_state = Device.GetState();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В случае с К++, чтение свойств осуществляется подобно обычным полям. Перепишем вышеописанный пример на язык К++: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
class MyDevice {&lt;br /&gt;
    function int GetState();&lt;br /&gt;
    property int state read GetState;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Соответственно, обращение к свойству состояния будет выглядеть так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var current_state = Device.state;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При обращении к свойству &amp;lt;tt&amp;gt;state&amp;lt;/tt&amp;gt;  будет автоматически вызван метод &amp;lt;tt&amp;gt;GetState()&amp;lt;/tt&amp;gt;, результат которого будет возвращен как значение свойства. Вышеописанный пример кому-то может показаться странным, ведь получается, что мы усложнили код класса ради сомнительного выигрыша в коде обращения. На самом деле, в реальных условиях, с настоящими классами, с большим количеством свойств и в сложных выражениях, выигрыш становится куда более заметен. Сравните два примера одного и того же участка кода, один из которых написан на C++, другой на K++. Несмотря на то, что приведенный код тоже взят &amp;quot;с потолка&amp;quot;, разница в читаемости уже более заметна. В целом, чем сложнее выражение и чем больше в нем применяется операций присваивания и доступа к полям классов — тем большее преимущество дает использование свойств:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
Object1.SetStatus(Object2.GetStatus() &amp;gt; 0 ? Object2.GetStatus() : DefaultObject.GetStatus());&lt;br /&gt;
printf(&amp;quot;object %s (%d) located at %s : status changed to %u&amp;quot;, &lt;br /&gt;
    Object1.GetName(), Object1.GetIndex(), Object1.GetLocation(), Object1.GetStatus());&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
Object1.status = Object2.status &amp;gt; 0 ? Object2.status : DefaultObject.status;&lt;br /&gt;
println(&amp;quot;object % (%) located at % : status changed to %&amp;quot;, &lt;br /&gt;
    Object1.name, Object1.index, Object1.location, Object1.status);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В качестве второго примера мы приведем код, более близкий к реальной жизни. Как известно, многие элементы управления современных графических интерфейсов могут находиться в состоянии &amp;quot;активен&amp;quot; или &amp;quot;не активен&amp;quot;. Неактивные элементы не реагируют на действия пользователя (например, кнопки не будут нажиматься) и как правило окрашиваются в оттенки серого (для того чтобы нельзя было их спутать с активными элементами). Естественно, это поведение определяется некоторым полем в объекте элемента управления. В зависимости от его значения, библиотека графического интерфейса будет по-разному обрабатывать и отрисовывать этот элемент управления.&lt;br /&gt;
&lt;br /&gt;
В языке К++ это поведение можно легко описать, используя двусторонние свойства, то есть такие, которые можно использовать как на чтение, так и на запись. Логично предположить, что чтение такого свойства не должно сказываться на самом элементе управления, в то время как запись в свойство должна дать команду элементу управления изменить свое состояние и соответственно внешний вид. Вот пример описания некоторого абстрактного класса элемента управления:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
class Widget {&lt;br /&gt;
    var m_Enabled = true; //поле, хранящее текущее состояние активности&lt;br /&gt;
    function void SetEnabled(const value) {&lt;br /&gt;
        var old_value = m_Enabled;&lt;br /&gt;
        m_Enabled = value;&lt;br /&gt;
        if (old_value != m_Enabled)&lt;br /&gt;
            Invalidate(); //Состояние изменилось, обновляем элемент управления&lt;br /&gt;
    }&lt;br /&gt;
    property enabled read m_Enabled write SetEnabled;&lt;br /&gt;
    //далее идет остальная часть класса, например методы отрисовки&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь, если мы унаследуем некоторый класс от данного класса и переопределим соответствующие методы отрисовки, то у класса потомка так же можно будет использовать свойство &amp;lt;tt&amp;gt;enabled&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var myForm = new Form; //создаем окно&lt;br /&gt;
var myButton = Button.CreateAtPos(myForm, 10, 10); //добавляем кнопку&lt;br /&gt;
myButton.caption = &amp;quot;Click me!&amp;quot;; //устанавливаем подпись&lt;br /&gt;
myButton.OnClick += { |x| x.enabled = false; }; //подключаем обработчик события&lt;br /&gt;
myForm.Show(); //показываем окно&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Приведенный выше код создаст окно и разместит на нем кнопку (подразумевается, что класс &amp;lt;tt&amp;gt;Button&amp;lt;/tt&amp;gt; унаследован от нашего класса &amp;lt;tt&amp;gt;Widget&amp;lt;/tt&amp;gt;). Затем устанавливаются свойства кнопки, такие как подпись и [[Блоки|блок]] обработчика события &amp;lt;tt&amp;gt;OnClick&amp;lt;/tt&amp;gt;. При нажатии на кнопку она станет неактивной.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
В заключение, кратко опишем синтаксис объявления свойства и поясним его. Итак, объявление любого свойства начинается с указания ключевого слова &amp;lt;tt&amp;gt;'''property'''&amp;lt;/tt&amp;gt;, после которого идет [[идентификатор]] типа свойства. Тип может быть опущен, тогда для свойства будет определен [[Переменные#Нетипированные (динамические) переменные|динамический тип]]. Затем указывается идентификатор имени свойства. &lt;br /&gt;
&lt;br /&gt;
Оставшаяся часть зависит от того, какое свойство объявляется:&lt;br /&gt;
&lt;br /&gt;
* Если объявляется свойство на чтение, то указывается ключевое слово &amp;lt;tt&amp;gt;'''read'''&amp;lt;/tt&amp;gt;, после которого идет либо идентификатор имени поля, которое нужно читать, либо имя метода, который должен использоваться как ''аксессор''. В роли аксессора может выступать метод, не принимающий параметров и возвращающий некоторое значение, которое будет возвращаться как значение свойства.&lt;br /&gt;
* Если объявляется свойство на запись, то указывается, соответственно ключевое слово &amp;lt;tt&amp;gt;'''write'''&amp;lt;/tt&amp;gt; после которого идет либо имя поля, которое нужно записывать, либо имя метода, который должен использоваться как ''мутатор''. В качестве мутатора может выступать метод, принимающий один параметр. Возвращаемое значение игнорируется, так что оно может быть любым.&lt;br /&gt;
* Если объявляется свойство, доступное как на чтение, так и на запись, то указываются обе части, причем первой идет часть чтения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' Если тип свойства указан явно, то в зависимости от типа поля либо типа возвращаемого значения аксессора, может быть выполнена операция [[Приведение типов|приведения типов]]. Разумеется, если тип поля или результат аксессора неприводим к указанному типу свойства, то будет выдано сообщение об ошибке. Аналогичная ситуация обстоит и с параметром мутатора.&lt;br /&gt;
&lt;br /&gt;
Кратко, синтаксис объявления свойства можно описать в стиле справки к командам оболочки:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
property [тип] &amp;lt;имя&amp;gt; [read &amp;lt;аксессор|поле&amp;gt;] [write &amp;lt;мутатор|поле&amp;gt;];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Расширения ==&lt;br /&gt;
&lt;br /&gt;
Иногда бывает необходимо расширить функциональность некоторого существующего класса без порождения дочернего класса. Это может быть необходимо в тех случаях, когда исходный класс уже используется в коде программы и порождение нового класса нарушило бы спецификацию на интерфейс, либо потребовало значительных изменений в исходных текстах программы. В таких случаях целесообразно применять т. н. ''расширения классов''. Синтаксически, конструкция расширения практически не отличается от конструкции объявления класса, однако методы и свойства, перечисленные в нем, дополняются к исходному классу, то есть наследования не происходит.&lt;br /&gt;
&lt;br /&gt;
Как правило, расширения применяются к классам [[Стандартной библиотека Gide|стандартной библиотеки]], либо к [[unmanaged код|неуправляемым классам]].&lt;br /&gt;
&lt;br /&gt;
В качестве примера приведем код, расширяющий функциональность класса &amp;lt;tt&amp;gt;[[Стандартные типы данных#Целые числа|int]]&amp;lt;/tt&amp;gt; с помощью свойства &amp;lt;tt&amp;gt;factorial&amp;lt;/tt&amp;gt;. Расширения объявляются путем указания ключевого слова &amp;lt;tt&amp;gt;'''extend'''&amp;lt;/tt&amp;gt;, после которого указывается [[идентификатор]] имени класса, который следует расширить. Затем идет тело расширения, такое же, как при описании классов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
package intmod_fact;&lt;br /&gt;
import std;&lt;br /&gt;
external console_stream STDOUT;&lt;br /&gt;
function void println(const string s) { STDOUT.print(s + &amp;quot;\n&amp;quot;); }&lt;br /&gt;
&lt;br /&gt;
extend int {&lt;br /&gt;
    const function ubigint GetFactorial() {&lt;br /&gt;
        var ubigint result = 1, int x;&lt;br /&gt;
        for (x = this; x &amp;gt; 1; --x)&lt;br /&gt;
            result *= x;&lt;br /&gt;
        return result;&lt;br /&gt;
    }&lt;br /&gt;
    property ubigint factorial read GetFactorial;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
export function main() {&lt;br /&gt;
    println(&amp;quot;Factorial of 10 is &amp;quot; + 10.factorial);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;6-14: Мы объявляем расширение класса &amp;lt;tt&amp;gt;[[Стандартные типы данных#Целые числа|int]]&amp;lt;/tt&amp;gt;, реализованного в [[Стандартная библиотека gide|стандартной библиотеке]]. Добавляется частный метод &amp;lt;tt&amp;gt;GetFactorial()&amp;lt;/tt&amp;gt;, и свойство &amp;lt;tt&amp;gt;factorial&amp;lt;/tt&amp;gt;, связанное с методом. Как видно из названия, метод рассчитывает факториал числа, которое содержится в объекте. В данном контексте, специальная переменная ''this'' имеет тип &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt; и ссылается на сам объект. Таким образом, для числа 10 переменная ''this'' будет равна 10.&lt;br /&gt;
&lt;br /&gt;
;17: Здесь мы видим применение расширения в действии. Константа 10 на момент компиляции преобразуется в [[Константы#Константные объекты|константный объект]] класса &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;, который подобно любому другому объекту этого же класса будет иметь свойство &amp;lt;tt&amp;gt;factorial&amp;lt;/tt&amp;gt;, которое мы и используем. При попытке чтения из этого свойства будет вызван метод &amp;lt;tt&amp;gt;GetFactorial()&amp;lt;/tt&amp;gt;, результат выполнения которого возвращается как значение свойства, то есть как факториал числа. &amp;lt;!--Его мы вызываем с помощью специального синтаксиса, для передачи блока в качестве [[Функции#Аргументы|параметра функции]]. При этом сам блок указывается прямо в коде вызова функции. Тело блока состоит из одного вызова функции, выводящей текущее число в стандартный поток вывода. --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
: Обратите внимание, что функция &amp;lt;tt&amp;gt;println()&amp;lt;/tt&amp;gt;, принимает в качестве параметра [[Стандартные типы данных#Строки|строку]], в то время как тип свойства определен как &amp;lt;tt&amp;gt;[[Стандартные типы данных#Целые числа|ubigint]]&amp;lt;/tt&amp;gt;. В этом нет ничего странного, потому что класс &amp;lt;tt&amp;gt;ubigint&amp;lt;/tt&amp;gt; имеет [[Типы операторов#Операторы приведения типов|оператор приведения типа]] к классу &amp;lt;tt&amp;gt;[[Стандартные типы данных#Строки|string]]&amp;lt;/tt&amp;gt;, который вызывается компилятором автоматически. Таким образом, при вычислении значения выражения в скобках, сперва значение факториала ''приводится'' к типу строки, которая складываясь со строкой слева от оператора &amp;lt;tt&amp;gt;+&amp;lt;/tt&amp;gt;, передается в качестве параметра функции.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' При работе с расширениями существует одно важное ограничение. Расширять классы можно только методами и свойствами, но не полями. Это связано с внутренней организацией языка К++ и виртуальной машины. Дополнительно стоит отметить, что методы объявленные в расширении будут перекрывать соответствующие им методы класса (имеется в виду ситуация когда имена и наборы параметров полностью совпадают). Важно понимать, что такое перекрытие не является объявлением виртуального метода — происходит именно замещение старого метода новым.&lt;br /&gt;
&lt;br /&gt;
== Смотри также ==&lt;/div&gt;</summary>
		<author><name>KroTozeR</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%9A%D0%BB%D0%B0%D1%81%D1%81%D1%8B_%D0%B8_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B</id>
		<title>Классы и объекты</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%9A%D0%BB%D0%B0%D1%81%D1%81%D1%8B_%D0%B8_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B"/>
				<updated>2007-10-05T11:36:00Z</updated>
		
		<summary type="html">&lt;p&gt;KroTozeR: /* Свойства */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== История развития ООП ==&lt;br /&gt;
&lt;br /&gt;
Для того чтобы понять, что же такое классы и объекты, сперва необходимо проследить историю развития программирования. А конкретнее, историю возникновения концепции ООП. Автор верит, что знание истории возникновения тех или иных мыслей и идей может помочь читателю осознать необходимость нововведений, и главное — их преимуществ перед существовавшими в то время решениями.&lt;br /&gt;
&lt;br /&gt;
=== Возникновение языков программирования ===&lt;br /&gt;
&lt;br /&gt;
На заре зарождения вычислительных машин их приходилось программировать поистине &amp;quot;вручную&amp;quot;. Все, что было в руках  программиста это пульт управления ЭВМ. На шестнадцатеричной клавиатуре (а еще раньше на пульте с тумблерами) программист задавал некоторый адрес ячейки памяти, затем он мог либо выполнить операцию чтения — тогда на табло появлялись цифры, соответствующие значению ячейки памяти, либо операцию записи — при этом, по указанному адресу записывалось значение, набранное на клавиатуре данных. Затем, программист переходил к следующей ячейке, и так повторялось до тех пор, пока в память ЭВМ не была внесена вся программа. На программистах (точнее, на операторах ЭВМ) лежала огромная ответственность! Одна ошибка, один неверно установленный переключатель или одна пропущенная команда неминуемо вели к ошибкам в работе программы, а, следовательно, и к ошибкам в расчетах. Могли потребоваться недели, и даже месяцы на поиск этой ошибки и на ее исправление! Естественно, ни о каких языках программирования тогда не могло идти и речи.&lt;br /&gt;
&lt;br /&gt;
=== Появление ассемблера ===&lt;br /&gt;
&lt;br /&gt;
Впоследствии, программисты смекнули, что команды можно записывать в виде мнемонических обозначений или мнемоник — то, что раньше применялось только для удобства записи на бумаге — было стандартизировано и приспособлено как ''язык'' общения человека и ЭВМ. Так появился первый язык программирования — ''язык ассемблера''. Конечно, языком его можно назвать с некоторой натяжкой, ведь он не обеспечивал и десятой доли тех возможностей (вроде автоматического разбора арифметических выражений), которые мы привыкли ассоциировать с языками программирования. Тем не менее, ассемблер выполнял свою главную и основную функцию — избавлял программиста от необходимости работать с памятью (и адресами) напрямую. Вместо этого, программист записывал свои команды в стандартной форме, понятной ЭВМ. Далее выполнялась программа ''транслятор'', которая преобразовывала исходный текст программы в поток машинных команд, которые уже можно исполнять.&lt;br /&gt;
&lt;br /&gt;
=== Концепция языка высокого уровня ===&lt;br /&gt;
&lt;br /&gt;
...С увеличением сложности программ, программировать на ассемблере становилось все сложнее и сложнее.  Ввиду естественных ограничений человеческой памяти и внимания, написание программ и их отладка стали настолько сложными, что люди всерьез подошли к рассмотрению идеи языка высокого уровня — некоторой системы обозначений и абстрактных команд, которая позволила бы записывать программы в абстрактной форме, не заботясь о том, как располагать в памяти код и данные, как их структурировать и т. д. Всю эту работу брал на себя компилятор. Кроме того, он обеспечивал программиста удобным способом записи математических выражений — в естественной форме. При этом, компилятор сам &amp;quot;разворачивал&amp;quot; эти выражения в наборы инструкций ассемблера, попутно подставляя значения констант и адреса переменных. Это дало возможность программистам записывать формулы вычислений в натуральном виде, что уменьшало трудозатраты, ускоряло написание программ и уменьшало вероятность ошибок. Тем не менее, многие авторитеты того времени очень негативно отзывались о языках высокого уровня. В то время языки были довольно несовершенными и генерировали &amp;quot;ужасный&amp;quot; с точки зрения программистов код. Код был не оптимален, занимал огромное по тем временам количество памяти и работал медленнее, чем та же программа, написанная на ассемблере. Смешно сказать, но в то время многие не верили в то, что будущее за ЯП высокого уровня; их считали не более чем игрушкой для &amp;quot;чайников&amp;quot;, возжелавших вообразить себя настоящими программистами. &lt;br /&gt;
&lt;br /&gt;
Но время шло, количество приверженцев нового подхода постоянно увеличивалось. Сами же компиляторы становились все более мощными и генерировали все более компактный и оптимальный код. Дошло до того, что компилятор с оптимизатором в некоторых случаях генерировал код, более качественный, чем это делал программист. С этого момента ЯП высокого уровня заняли свое место в истории и в инструментарии любого разработчика.&lt;br /&gt;
&lt;br /&gt;
=== Структурное программирование ===&lt;br /&gt;
&lt;br /&gt;
С развитием языков программирования появились новые концепции и новые парадигмы программирования. От линейного моноблочного программирования, при котором программа писалась единым &amp;quot;куском&amp;quot; от начала до конца, перешли к программам модульным и структурным. При них программа представляла уже совокупность процедур (функций), которые вызывали друг друга в ходе работы программы. Процедуры представляли собой подпрограммы, решающие отдельные частные задачи. При этом код получался более читаемым, и облегчалась его отладка. &lt;br /&gt;
&lt;br /&gt;
Опять же, в ходе усложнения решаемых задач и, вследствие этого, увеличения количества переменных с которыми приходилось работать программисту, возникла идея группировки некоторых переменных в группы или структуры. Структуры формировались по назначению и содержали в себе переменные, имеющие отношение к одной и той же сущности. Это значительно повысило читаемость программ и уменьшило количество ошибок в них.&lt;br /&gt;
&lt;br /&gt;
=== Объектно-ориентированное программирование ===&lt;br /&gt;
&lt;br /&gt;
Ну и наконец, одна светлая голова додумалась до мысли: &amp;quot;а что если в структурах группировать не только переменные, но и сами процедуры которые должны работать с этими переменными?&amp;quot;. В результате получилось то, что мы сейчас называем классом — то есть, некоторая обособленная функциональная сущность, которая сама хранит свои данные, а главное сама умеет их обрабатывать. Теперь программисту не нужно помнить, какая из процедур отвечает за некоторое действие над такими-то переменными — он просто берет объект и работает с ним. Все что происходит с объектом внутри — это его личное дело.&lt;br /&gt;
&lt;br /&gt;
Последним шагом к современному пониманию программ явились концепции [http://ru.wikipedia.org/wiki/Полиморфизм_(программирование) полиморфизма], [http://ru.wikipedia.org/wiki/Инкапсуляция_(программирование) инкапсуляции] и [http://ru.wikipedia.org/wiki/Наследование_(программирование) наследования]. Не будем пока углубляться в суть этих понятий, отметим только, что их введение сформировало современное понимание объектно-ориентированного программирования.&lt;br /&gt;
&lt;br /&gt;
При написании программы на объектно-ориентированном языке, программист строит математическую модель взаимодействия различных сущностей. Каждая из сущностей это свой мир, у которого есть свои законы и особенности. При этом сущности могут быть как конкретные, вроде &amp;quot;сетевой интерфейс&amp;quot; или &amp;quot;файл&amp;quot;, так и совершенно абстрактные, например &amp;quot;отношение&amp;quot; или &amp;quot;ошибка&amp;quot;. Программист описывает каждую из сущностей в отдельности, обособлено от остальных. Вся необходимая для работы информация хранится внутри, а для взаимодействия с внешним миром предусмотрен ''интерфейс'' — некоторая совокупность ''свойств'' данной сущности (отражающих ее внутреннее состояние) и способов взаимодействия с ней — ''методов''.&lt;br /&gt;
&lt;br /&gt;
В ходе работы программы сущности могут взаимодействовать, читая и записывая свойства и вызывая методы друг друга, использовать друг друга как подсистемы, порождать новые сущности и т. д. Получается, что при написании программы, программист переносит свое внутреннее представление того как он видит эту программу, то из чего она состоит и как отдельные ее части взаимодействуют. Теперь не приходится адаптировать свое понимание проблемы к конкретным инструментальным средствам и возможностям языка программирования (конечно, это все же происходит, но уже гораздо менее заметно).&lt;br /&gt;
&lt;br /&gt;
В терминах современных языков программирования такие сущности называются ''классами'', в смысле ''классами сущностей''. А отдельные представители этих классов называются ''экземплярами'', ''инстанциями'' (на английский манер) или ''объектами''. Более подробно, различие между классами и объектами будет рассмотрено ниже.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Итак, любой современный объектно-ориентированный язык оперирует понятиями классов и объектов. Точно такой же подход нашел свое применение в нашей виртуальной машине. Основой всей платформы Gide является объектно-ориентированный принцип. Причем, в этом смысле она является более объектно-ориентированной, нежели традиционные ЯП вроде C++. В C++ существуют понятия элементарных типов. Это сделано в целях производительности и было продиктовано архитектурой самого языка. В классических языках программирования, элементарные типы, так или иначе, отражают сущности из &amp;quot;реального мира&amp;quot;. Например, целочисленные типы int и short соответствуют 32х и 16ти разрядным регистрам процессора, указатели и строки соответствуют представлению данных в памяти и т. д. В Gide это не так. Все с чем оперирует виртуальная машина — это объекты. Соответственно, не существует понятия элементарных типов (просто нет критерия, который бы позволил отделить одно от другого). &lt;br /&gt;
&lt;br /&gt;
Язык K++ в полной мере наследует идеологию Gide. Скажем, для него нет отличия между типом &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt; (целое число) и некоторым пользовательским классом &amp;lt;tt&amp;gt;MyWeirdClass&amp;lt;/tt&amp;gt;: везде, где можно использовать &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;, можно использовать &amp;lt;tt&amp;gt;MyWeirdClass&amp;lt;/tt&amp;gt; и наоборот. Более того, это позволяет работать с системными классами так же, как с пользовательскими! Например, ничто не мешает унаследовать свой класс от класса &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;, равно как ничто не мешает определить математические операторы для класса &amp;lt;tt&amp;gt;MyWeirdClass&amp;lt;/tt&amp;gt; и использовать объекты этого класса в арифметических выражениях. При этом изменится логика работы всего языка. К примеру, после добавления некоторого метода к классу int можно будет вызывать методы у всех его экземпляров, даже тех, что представлены числовыми константами внутри самого языка!&lt;br /&gt;
&lt;br /&gt;
== Понятие класса ==&lt;br /&gt;
&lt;br /&gt;
Что такое ''класс'' проще всего объяснить на примерах. Представьте, что вас спрашивают &amp;quot;что такое яблоко?&amp;quot;. Скорее всего, вы ответите что-то вроде: &amp;quot;яблоки, это вкусные плоды, растущие на деревьях — яблонях; они бывают разных цветов и размеров&amp;quot;. Заметьте, что когда мы описываем ''яблоки как понятие'', мы не имеем в виду некоторый конкретный объект, а скорее описываем наше обобщенное представление о них. Если же вас попросят описать совершенно конкретное яблоко, лежащее на блюдечке перед вами, вы будете говорить о нем по другому: &amp;quot;это яблоко, оно красное, сочное, судя по всему спелое. С черенком, на котором остался листик, и маленькой червоточинкой&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Разница заключается в том, что когда вы говорили ''о яблоках'', вы описывали свое представление яблок, как ''класса'' объектов. Когда вы описывали ''яблоко'', то вы имели в виду конкретный ''экземпляр'', или ''объект''. Говоря о классе, вы можете описать только те свойства, что принадлежат всем яблокам; когда же вы описываете объект, то в первую очередь имеете в виду его индивидуальные особенности (свойства). Тем не менее, описание объекта начинается с упоминания его класса (&amp;quot;это яблоко,...&amp;quot;), а затем уже свойств объекта (ведь &amp;quot;сочным и спелым&amp;quot; может быть и апельсин). Это важная особенность объектно-ориентированного подхода. &lt;br /&gt;
&lt;br /&gt;
Другой пример: если вас попросить &amp;quot;представьте дерево&amp;quot;, то вы либо представите некоторое совершенно абстрактное, усредненное дерево, либо попросите уточнить, какое именно дерево имеется в виду. Ваше сознание из имеющейся информации смогло уяснить только самые общие сведения о классе. Но этой информации не достаточно, для более детального описания. Это тоже важно, поскольку в этом простом примере кроется сущность механизма наследования — постепенного уточнения классами-потомками общих черт своих предков. Таким образом, и яблоня, и груша — деревья. Но яблони отличаются от груш. Получается, что классы ''яблони'' и ''груши'' имеют общего предка — класс ''дерево''.&lt;br /&gt;
&lt;br /&gt;
Таким образом, понятия классов и объектов это не математическая абстракция, а скорее часть нашего восприятия мира, того как мы мыслим.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из примеров выше мы смогли уяснить следующее:&lt;br /&gt;
&lt;br /&gt;
* Классы, это некоторые абстрактные сущности, задающие общие черты своих объектов&lt;br /&gt;
* Все объекты одного класса похожи друг на друга, но имеют некоторые индивидуальные особенности&lt;br /&gt;
* Классы могут наследоваться, расширяя набор свойств класса родителя своими собственными&lt;br /&gt;
&lt;br /&gt;
Перейдем теперь ближе к основной теме нашего повествования, а именно языку К++:&lt;br /&gt;
&lt;br /&gt;
С точки зрения языка, ''класс'' представляет собой набор следующих элементов:&lt;br /&gt;
* ''полей'', т.е. переменных, хранящих индивидуальные особенности объектов, &lt;br /&gt;
* ''методов'', т.е. функций, определяющих поведение данного объекта;&lt;br /&gt;
* ''свойств'', определяющих взаимодействие других объектов с объектами данного класса.&lt;br /&gt;
&lt;br /&gt;
''Поля'' — это переменные, которые относятся к некоторому конкретному экземпляру нашего класса. Каждый экземпляр имеет свою копию набора переменных, таким образом, они могут хранить свое состояние (например, показатель &amp;quot;спелости&amp;quot;, в примере с яблоками). Эти переменные доступны только самому классу, доступ извне для них запрещен. Для того чтобы частично разрешить этот доступ, применяются ''свойства''. Сами свойства будут описаны позже, здесь стоит отметить только то, что свойство может быть доступно &amp;quot;только на чтение&amp;quot;, &amp;quot;только на запись&amp;quot; или &amp;quot;и на чтение и на запись&amp;quot;. Свойство может быть связано либо с некоторым полем, либо с методом. Например, если свойство доступно &amp;quot;только на чтение&amp;quot; то его можно использовать для получения значения, но не для его записи (то есть, такое свойство не может фигурировать в качестве [[lvalue]]).&lt;br /&gt;
&lt;br /&gt;
''Методы'' — это тот самый, связанный с данными код (вспомните [[Классы и объекты#История развития ООП|историю ООП]]) который, естественно, может работать с переменными объекта (то есть с полями) и служит для описания поведения данного класса объектов.&lt;br /&gt;
&lt;br /&gt;
Класс может иметь одного или нескольких родителей (опять же, подробнее об этом см. ниже)&lt;br /&gt;
&lt;br /&gt;
Методы и свойства класса могут находиться в различных областях видимости. Это обеспечивается с помощью [[Спецификаторы доступа|спецификаторов доступа]]:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''private'''&amp;lt;/tt&amp;gt; — Частная собственность! Видимость только внутри методов данного класса&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''protected'''&amp;lt;/tt&amp;gt; — &amp;quot;Семейная реликвия&amp;quot;, доступ внутри методов данного класса и всех его дочерних классов&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''public'''&amp;lt;/tt&amp;gt; — видимость и доступ для всех&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' По умолчанию методы имеют видимость &amp;lt;tt&amp;gt;'''private'''&amp;lt;/tt&amp;gt;, в то время как свойства — &amp;lt;tt&amp;gt;'''public'''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Приведем, наконец, пример объявления класса:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
class MyWeirdClass {&lt;br /&gt;
    var m_x = 0;  // поле m_x, изначально проинициализированное нулем&lt;br /&gt;
    const m_y = 1; // поле-константа m_y&lt;br /&gt;
&lt;br /&gt;
    // методы класса&lt;br /&gt;
    public const function int get_mul() { return m_x * m_y; }&lt;br /&gt;
    public function void set_mul(int x) { m_x = x / m_y; }&lt;br /&gt;
&lt;br /&gt;
    // свойство класса&lt;br /&gt;
    public property mul read get_mul write set_mul;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;1: Как у любого нормального разумного существа, у класса есть &amp;quot;голова&amp;quot; и &amp;quot;тело&amp;quot;. Ключевое слово &amp;lt;tt&amp;gt;'''class'''&amp;lt;/tt&amp;gt; начинает объявление класса. Далее за ним следует [[идентификатор]] имени класса, после чего идет тело класса.&lt;br /&gt;
&lt;br /&gt;
;3-4: Здесь мы видим объявление двух полей класса — переменной ''m_x'' и константы ''m_y'', которые, подобно обычным переменным инициализируются тут же, на месте объявления (камень в огород C++). Зачем нужны поля-константы, описано в главе [[Константы]].  &lt;br /&gt;
&lt;br /&gt;
;7-8: Для доступа к состоянию объекта, определены два метода: ''аксессор'' &amp;lt;tt&amp;gt;get_mul()&amp;lt;/tt&amp;gt; и ''мутатор'' &amp;lt;tt&amp;gt;set_mul()&amp;lt;/tt&amp;gt;. Подобные конструкции применяются настолько часто, что им были даны специальные имена. Как видно из названия, первый метод дает доступ к значению, второй изменяет или мутирует его.&lt;br /&gt;
&lt;br /&gt;
;11: Завершается объявление класса объявлением свойства ''mul'', которое связывается с аксессором и мутатором. Думаю, читатель уже догадался, что это свойство типа &amp;quot;чтение и запись&amp;quot;. Таким образом, при обращении к свойству на чтение, будет вызван аксессор, а результат его выполнения будет возвращен в качестве значения свойства. И, наоборот, при попытке записать в свойство некоторое значение, будет вызван мутатор, в качестве аргумента которому будет передано это самое значение, а уж сам мутатор позаботится о том, чтобы оно было &amp;quot;доставлено по адресу&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
: '''Примечание:''' Зачем нужны такие сложности, и зачем дублировать вроде бы одинаковый функционал, будет описано ниже.&lt;br /&gt;
&lt;br /&gt;
== Понятие объекта ==&lt;br /&gt;
&lt;br /&gt;
Собственно, понятие объекта уже много раз было затронуто выше по повествованию. Поэтому здесь приведем лишь небольшое определение: Под ''объектом'' подразумевается экземпляр того или иного класса, т.е. некоторая сущность, поведение которой задается соответствующим классом.&lt;br /&gt;
&lt;br /&gt;
Для создания объекта того или иного класса служит оператор &amp;lt;tt&amp;gt;'''new'''&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
    var myWeirdObject = new MyWeirdClass;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь мы видим типичную конструкцию объявления переменной, однако в инициализаторе переменной находится всего один оператор, за которым следует [[идентификатор]] имени класса, экземпляр которого мы хотим создать.&lt;br /&gt;
&lt;br /&gt;
== Наследование ==&lt;br /&gt;
&lt;br /&gt;
Под ''наследованием'' классов понимается механизм такого создания (объявления) класса, при котором он расширяет функционал одного или нескольких уже существующих классов (родителей). Вспомните пример с деревьями. Когда мы говорим, что класс ''яблоня'' наследуется от класса ''дерево'' — это значит что ''яблоня'' унаследует все свойства своего класса-родителя, некоторые из которых он может изменить, ну и дополнить своими собственными свойствами. Опыт нам подсказывает, что у любого дерева есть листья (для простоты не будем вспоминать про хвойные), однако не любое дерево плодоносит яблоками. Если же рассмотреть сами яблоки, то можно сказать, что класс ''яблоко'' унаследован от класса ''фрукт'', который определяет что фрукты (и соответственно яблоки) должны расти на деревьях.&lt;br /&gt;
&lt;br /&gt;
Таким образом, наследование гарантирует, что к дочерним классам применимы все операции, доступные в родительском классе: любой алгоритм, работающий с объектами родительского класса, может работать с объектами его дочерних классов. &lt;br /&gt;
&lt;br /&gt;
Для задания наследования, в объявлении класса следует указать ключевое слово &amp;lt;tt&amp;gt;'''extends'''&amp;lt;/tt&amp;gt;,  за которым необходимо перечислить список идентификаторов классов-родителей, разделяя их запятыми:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
// коробка&lt;br /&gt;
class Box { &lt;br /&gt;
    // из чего сделана коробка?&lt;br /&gt;
    public const function string material() { return &amp;quot;Картон&amp;quot;; }&lt;br /&gt;
&lt;br /&gt;
    // что в коробке?&lt;br /&gt;
    public const function string contents() { return &amp;quot;Пусто&amp;quot;; }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// коробка с картошкой&lt;br /&gt;
class BoxWithPotatoes extends Box { &lt;br /&gt;
    public const function string contents() { return &amp;quot;Картошка&amp;quot;; }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function OutputBox(const Box b) {&lt;br /&gt;
    STDOUT.print(&amp;quot;Материал: &amp;quot; + b.material() + &amp;quot;, содержит: &amp;quot; + b.contents() + &amp;quot;\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function main() {&lt;br /&gt;
    var b1 = new Box;&lt;br /&gt;
    var b2 = new BoxWithPotatoes;&lt;br /&gt;
    OutputBox(b1); // Материал: Картон, содержит: Пусто&lt;br /&gt;
    OutputBox(b2); // Материал: Картон, содержит: Картошка&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;2-7: В этом примере мы создаем класс &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt;, который представляет собой некоторую коробку. Мы определяем ее свойства, такие как ''материал'' и ''содержимое''.&lt;br /&gt;
&lt;br /&gt;
;10-12: Далее мы определяем класс &amp;lt;tt&amp;gt;BoxWithPotatoes&amp;lt;/tt&amp;gt; (''коробка с картошкой''), который наследуется от класса &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt;, и тем самым заимствует свойства материала и содержимого, но первое он переопределяет (в случае методов это называется ''перекрытием'') собственным методом.&lt;br /&gt;
&lt;br /&gt;
;14-16: Мы определяем некоторую [[Функции|функцию]] для работы с нашими классами, которая будет отображать их состояние. Заметьте, что в качестве [[Функции#Аргументы|аргумента функции]] передается экземпляр класса &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt;, то есть класса-родителя. При этом мы предполагаем, что любой класс, унаследованный от базового класса, будет обладать необходимым нам интерфейсом, а именно методами получения информации о свойствах (аксессорами мы их не называем, потому что они не связаны с конкретным полем; это было бы неверно).&lt;br /&gt;
&lt;br /&gt;
;18-23: Объявляется функция &amp;lt;tt&amp;gt;main()&amp;lt;/tt&amp;gt;, внутри которой и происходит самое интересное. Сначала мы создаем два экземпляра ''b1'' и ''b2'' классов &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt; и &amp;lt;tt&amp;gt;BoxWithPotatoes&amp;lt;/tt&amp;gt; соответственно. А затем, вызываем вышеописанную функцию &amp;lt;tt&amp;gt;OutputBox()&amp;lt;/tt&amp;gt;, которая отображает содержимое. Вывод в терминал (написан в комментарии к вызову) показывает, как это все работает.&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' при использовании множественного наследования существует одно серьезное ограничение: его нельзя применять для наследования от классов стандартной библиотеки. Это ограничение связано с архитектурой платформы Gide. Однако его можно обойти с помощью создания [[Класс-обертка|классов-оберток]] для системного класса, с последующим наследованием от него нового класса.&lt;br /&gt;
&lt;br /&gt;
== Методы ==&lt;br /&gt;
&lt;br /&gt;
''Метод'' — это некоторый код, связанный с объектом и управляющий его поведением. Управление может заключаться в изменении переменных состояния объекта (полей), либо выполнением некоторых операций над ними.&lt;br /&gt;
&lt;br /&gt;
При объявлении метода могут быть указаны следующие ключевые слова, в указанном порядке:&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''private'''&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;'''protected'''&amp;lt;/tt&amp;gt; или &amp;lt;tt&amp;gt;'''public'''&amp;lt;/tt&amp;gt; — определяют область видимости метода&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''static'''&amp;lt;/tt&amp;gt; — указывает, что метод является ''статическим'' (см. ниже)&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''const'''&amp;lt;/tt&amp;gt; — метод не изменяет объект&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''function'''&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;'''operator'''&amp;lt;/tt&amp;gt; или &amp;lt;tt&amp;gt;'''constructor'''&amp;lt;/tt&amp;gt; указывает, что объявляется: ''метод'', ''[[Операторы|оператор]]'' или ''конструктор'' (см. ниже)&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''const'''&amp;lt;/tt&amp;gt; — метод возвращает результат, который нельзя изменять&lt;br /&gt;
&lt;br /&gt;
После этого указывается тип, возвращаемый методом. Если он опущен — возвращается [[Переменные#Нетипированные (динамические) переменные|динамическая переменная]]; если вместо типа указано ключевое слово &amp;lt;tt&amp;gt;'''void'''&amp;lt;/tt&amp;gt; — метод не возвращает результата. Следом за типом идет имя метода, затем — перечисление [[Функции#Аргументы|аргументов]] в скобках. Подробнее об объявлении функций и передаче параметров, можно прочитать в главе [[Функции]].&lt;br /&gt;
&lt;br /&gt;
Тело метода может быть объявлено как непосредственно в теле класса, так и вынесено за его пределы, например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
class MyClass {&lt;br /&gt;
    public const function string F1() { return &amp;quot;smth&amp;quot;; }&lt;br /&gt;
    public const function string F2();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function string MyClass::F2() {&lt;br /&gt;
    return F1();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;6: При вынесении функции за пределы класса, имя соответствующего метода предваряется именем класса, из которого он был вынесен; имена отделяются друг от друга символом &amp;quot;двойное двоеточие&amp;quot; ( &amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt; ); дополнительно — в заголовке вынесенной функции необходимо указать тип возвращаемого значения и параметры функции, все остальные ключевые слова указывать не обязательно.&lt;br /&gt;
&lt;br /&gt;
;7: В теле метода доступны все поля, методы и свойства данного класса и его предков. Например, в коде приведенном выше, метод &amp;lt;tt&amp;gt;F2()&amp;lt;/tt&amp;gt; вызывает метод &amp;lt;tt&amp;gt;F1()&amp;lt;/tt&amp;gt; для того же объекта.&lt;br /&gt;
&lt;br /&gt;
=== Статические методы ===&lt;br /&gt;
&lt;br /&gt;
''Статический метод класса'' — это метод, относящийся к данному классу, но не объекту этого класса. Т.е. это некоторая вспомогательная для данного класса функция.&lt;br /&gt;
&lt;br /&gt;
При объявлении статического метода нужно указать ключевое слово &amp;lt;tt&amp;gt;'''static'''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В теле статического метода нет возможности напрямую обращаться к другим методам данного класса, т.к. статическому методу недоступен объект класса. Фактически, единственным отличием статического метода от обычной функции является то, что такой метод может обращаться к защищенным полям и методам класса некоторого другого объекта. Подобный подход широко применяется при написании ''конструкторов'' (см. ниже).&lt;br /&gt;
&lt;br /&gt;
Пример:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
class MyClass {&lt;br /&gt;
    public static function string Info() { return &amp;quot;Я MyClass!&amp;quot;; }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function f() {&lt;br /&gt;
    // Вызов статического метода:&lt;br /&gt;
    var myClassInfo = MyClass.Info();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Конструкторы ===&lt;br /&gt;
&lt;br /&gt;
В ходе написания программы часто приходится создавать новые объекты. При этом объекту требуется установить некоторое начальное состояние. Разумеется, это выполняется либо путем написания инициализаторов соответствующих полей, либо значения полям присваиваются явным образом. Но что делать, если объект может иметь несколько начальных состояний? То есть, в зависимости от некоторых условий, одним и тем же полям объекта могут быть присвоены различные наборы значений. Тут уже одними инициализаторами не обойтись. Присваивать значения можно прямо в коде программы, однако это не очень красивое решение, поскольку один и тот же объект может создаваться в нескольких местах программы и придется копировать один и тот же участок кода, инициализирующий поля объекта. Недостаток этого подхода в том, что при большом количестве полей, программист может забыть проинициализировать некаторе поле, либо при изменении условий инициализации он может изменить их только в одном месте программы, забыв, что объект может создаваться и в других местах. Более разумным является подход, при котором программист пишет функцию, инициализирующую поля объекта. При этом весь код собирается в одном месте и вероятность ошибок значительно понижается. &lt;br /&gt;
&lt;br /&gt;
Конструкторы развивают эту идею, дополняя код инициализации полей кодом создания самого экземпляра объекта. То есть, в конструкторе собирается весь код, относящийся к созданию инстанции класса. Итак, ''конструктор класса'' — это специальный метод, инициализирующий объект класса. С точки зрения языка, конструктор — это статический метод класса, возвращающий экземпляр данного класса.&lt;br /&gt;
&lt;br /&gt;
Таким образом, следующие объявления в рамках класса эквивалентны:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
public constructor Create();&lt;br /&gt;
public static MyClass Create();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тело конструктора чаще всего выглядит следующим образом: сначала создается экземпляр класса при помощи оператора &amp;lt;tt&amp;gt;'''new'''&amp;lt;/tt&amp;gt;, затем производятся некоторые действия, инициализующие этот объект, и, наконец, этот объект возвращается в качестве результата. &lt;br /&gt;
&lt;br /&gt;
В качестве примера приведем пример реализации некоторого абстрактного класса &amp;lt;tt&amp;gt;MyStream&amp;lt;/tt&amp;gt;, использующего системную реализацию класса &amp;lt;tt&amp;gt;stream&amp;lt;/tt&amp;gt;, и определяющую собственный конструктор:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
class MyStream {&lt;br /&gt;
    var string m_URL;&lt;br /&gt;
    var stream m_Stream;&lt;br /&gt;
public:&lt;br /&gt;
    static const MODE_READ = 1;&lt;br /&gt;
    static const MODE_WRITE = 2;&lt;br /&gt;
    constructor open(const string url, int mode) {&lt;br /&gt;
        var self = new MyStream;&lt;br /&gt;
        self.m_Stream.open(url, mode);&lt;br /&gt;
        self.m_URL = url;&lt;br /&gt;
        return self;&lt;br /&gt;
    }&lt;br /&gt;
    // прочие методы (опущены для краткости)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;2-3: Объявляются поля ''m_URL'' и ''m_Stream'' нашего класса, которые будут инициализироваться в конструкторе. &lt;br /&gt;
&lt;br /&gt;
;5-6: В публичной области класса объявляются статические константы ''MODE_READ'' и ''MODE_WRITE'', которые задают желаемый режим доступа к открываемому потоку. Это единственный случай, когда поле класса доступно на прямой доступ извне.&lt;br /&gt;
&lt;br /&gt;
;7: Объявляется конструктор &amp;lt;tt&amp;gt;open()&amp;lt;/tt&amp;gt;, принимающий в качестве параметров [[URL]] ресурса который требуется открыть и число, задающее с помощью вышеописанных констант режим доступа к потоку. В теле конструктора мы создаем инстанцию ''self'' нашего класса. Затем производится попытка открытия потока ''m_Stream'': если операция пройдет успешно, то происходит инициализация оставшегося поля ''m_URL'' и выход из конструктора с возвратом созданной инстанции; если же операция открытия потока провалится, то будет сгенерировано ''[[Обработка исключений|исключение]]'' и выполнение конструктора прекратится (управление будет передано &amp;quot;наверх&amp;quot;, вызывающему коду).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Использовать наш класс можно примерно так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;var data = MyStream.open(&amp;quot;http://www.deeptown.org/index.html&amp;quot;, MyStream.MODE_READ);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на второй параметр функции, где мы передаем константу ''MODE_READ'', объявленную внутри самого класса. Подобный подход, когда константы, используемые при работе с классом, инкапсулируются в тело класса, помогает сконцентрировать код в одном месте и избежать многих ошибок. В результате повышается читаемость кода и не возникает конфликта имен констант.&lt;br /&gt;
&lt;br /&gt;
== Поля ==&lt;br /&gt;
&lt;br /&gt;
Поле класса — это некоторый объект, используемый объектом данного класса.&lt;br /&gt;
&lt;br /&gt;
Объявление поля начинается с одного из трех ключевых слов:&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''var'''&amp;lt;/tt&amp;gt;  — объявление &amp;quot;обычного&amp;quot; поля;&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''const'''&amp;lt;/tt&amp;gt; — данное поле является константой и не может быть изменено;&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''mutable'''&amp;lt;/tt&amp;gt; — значение данного поля не влияет на состояние объекта, и его можно менять даже в методах, объявленных константными.&lt;br /&gt;
&lt;br /&gt;
За ключевым словом следует тип поля и [[идентификатор]] его имени. Тип поля может быть опущен. После имени может стоять символ &amp;quot;=&amp;quot; и выражение, инициализирующее значение данного поля. В целом, синтаксис тот же, что и при объявлении обычной переменой или константы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var int m_x;&lt;br /&gt;
const m_y = 0;&lt;br /&gt;
var m_stream = new stream;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тип поля определяется по следующим правилам:&lt;br /&gt;
* если тип указан явно, ничего определять не надо;&lt;br /&gt;
* если тип не указан, но при объявлении использован инициализатор — типом становится тип результата инициализатора;&lt;br /&gt;
* в противном случае, для поля устанавливается [[Переменные#Нетипированные (динамические) переменные|динамический тип]].&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' В K++ доступ к полям имеет только объект класса — т.е. фактически, все поля находятся в закрытой (private) области видимости. Для предоставления внешним классам доступа к полям следует использовать ''свойства'' (см. ниже).&lt;br /&gt;
&lt;br /&gt;
== Свойства ==&lt;br /&gt;
&lt;br /&gt;
''Свойства'' — это специальные конструкции языка К++, которые позволяют совмещать обращение к данным с вызовом определенного метода. Смысл свойств заключается в том, чтобы программист мог контролировать процесс изменения состояния объекта и своевременно реагировать на это изменение. Свойства бывают доступны на чтение, на запись, или на чтение и на запись одновременно. Это связано с тем, что некоторые свойства объекта (в естественном понимании этого слова), могут предполагать только получение информации о них, другие же могут подразумевать изменение состояния, без возможности чтения. &lt;br /&gt;
&lt;br /&gt;
В существующих языках программирования, таких как C++ тот же функционал реализуется с помощью вызова специальных методов: ''аксессоров'' и ''мутаторов'', которые используются для получения сведений о некотором свойстве или для записи соответственно. Однако это делает код менее читаемым, особенно в случае мутаторов. Свойства же, позволяют работать с собой подобно обычным полям или объектам, используя операторы. &lt;br /&gt;
&lt;br /&gt;
Приведем два примера, которые позволят понять смысл свойств и их отличие от обычных полей класса.&lt;br /&gt;
&lt;br /&gt;
Предположим, что у нас есть класс, отвечающий за чтение состояния некоторого устройства. Допустим, состояние представляется целым числом и должно определяться по мере обращения. Если бы мы писали на языке C++, то мы оформили бы это в виде метода:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
class MyDevice {&lt;br /&gt;
    int GetState();&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Везде, где нам потребовалось бы читать состояние устройства мы должны были писать что-то типа:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int current_state = Device.GetState();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В случае с К++, чтение свойств осуществляется подобно обычным полям. Перепишем вышеописанный пример на язык К++: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
class MyDevice {&lt;br /&gt;
    function int GetState();&lt;br /&gt;
    property int state read GetState;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Соответственно, обращение к свойству состояния будет выглядеть так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var current_state = Device.state;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При обращении к свойству &amp;lt;tt&amp;gt;state&amp;lt;/tt&amp;gt;  будет автоматически вызван метод &amp;lt;tt&amp;gt;GetState()&amp;lt;/tt&amp;gt;, результат которого будет возвращен как значение свойства. Вышеописанный пример кому-то может показаться странным, ведь получается, что мы усложнили код класса ради сомнительного выигрыша в коде обращения. На самом деле, в реальных условиях, с настоящими классами, с большим количеством свойств и в сложных выражениях, выигрыш становится куда более заметен. Сравните два примера одного и того же участка кода, один из которых написан на C++, другой на K++. Несмотря на то, что приведенный код тоже взят &amp;quot;с потолка&amp;quot;, разница в читаемости уже более заметна. В целом, чем сложнее выражение и чем больше в нем применяется операций присваивания и доступа к полям классов — тем большее преимущество дает использование свойств:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
Object1.SetStatus(Object2.GetStatus() &amp;gt; 0 ? Object2.GetStatus() : DefaultObject.GetStatus());&lt;br /&gt;
printf(&amp;quot;object %s (%d) located at %s : status changed to %u&amp;quot;, &lt;br /&gt;
    Object1.GetName(), Object1.GetIndex(), Object1.GetLocation(), Object1.GetStatus());&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
Object1.status = Object2.status &amp;gt; 0 ? Object2.status : DefaultObject.status;&lt;br /&gt;
println(&amp;quot;object % (%) located at % : status changed to %&amp;quot;, &lt;br /&gt;
    Object1.name, Object1.index, Object1.location, Object1.status);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В качестве второго примера мы приведем код, более близкий к реальной жизни. Как известно, многие элементы управления современных графических интерфейсов могут находиться в состоянии &amp;quot;активен&amp;quot; или &amp;quot;не активен&amp;quot;. Неактивные элементы не реагируют на действия пользователя (например, кнопки не будут нажиматься) и как правило окрашиваются в оттенки серого (для того чтобы нельзя было их спутать с активными элементами). Естественно, это поведение определяется некоторым полем в объекте элемента управления. В зависимости от его значения, библиотека графического интерфейса будет по-разному обрабатывать и отрисовывать этот элемент управления.&lt;br /&gt;
&lt;br /&gt;
В языке К++ это поведение можно легко описать, используя двусторонние свойства, то есть такие, которые можно использовать как на чтение, так и на запись. Логично предположить, что чтение такого свойства не должно сказываться на самом элементе управления, в то время как запись в свойство должна дать команду элементу управления изменить свое состояние и соответственно внешний вид. Вот пример описания некоторого абстрактного класса элемента управления:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
class Widget {&lt;br /&gt;
    var m_Enabled = true; //поле, хранящее текущее состояние активности&lt;br /&gt;
    function void SetEnabled(const value) {&lt;br /&gt;
        var old_value = m_Enabled;&lt;br /&gt;
        m_Enabled = value;&lt;br /&gt;
        if (old_value != m_Enabled)&lt;br /&gt;
            Invalidate(); //Состояние изменилось, обновляем элемент управления&lt;br /&gt;
    }&lt;br /&gt;
    property enabled read m_Enabled write SetEnabled;&lt;br /&gt;
    //далее идет остальная часть класса, например методы отрисовки&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь, если мы унаследуем некоторый класс от данного класса и переопределим соответствующие методы отрисовки, то у класса потомка так же можно будет использовать свойство &amp;lt;tt&amp;gt;enabled&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var myForm = new Form; //создаем окно&lt;br /&gt;
var myButton = Button.CreateAtPos(myForm, 10, 10); //добавляем кнопку&lt;br /&gt;
myButton.caption = &amp;quot;Click me!&amp;quot;; //устанавливаем подпись&lt;br /&gt;
myButton.OnClick += { |x| x.enabled = false; }; //подключаем обработчик события&lt;br /&gt;
myForm.Show(); //показываем окно&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Приведенный выше код создаст окно и разместит на нем кнопку (подразумевается, что класс &amp;lt;tt&amp;gt;Button&amp;lt;/tt&amp;gt; унаследован от нашего класса &amp;lt;tt&amp;gt;Widget&amp;lt;/tt&amp;gt;). Затем устанавливаются свойства кнопки, такие как подпись и [[Блоки|блок]] обработчика события &amp;lt;tt&amp;gt;OnClick&amp;lt;/tt&amp;gt;. При нажатии на кнопку она станет неактивной.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
В заключение, кратко опишем синтаксис объявления свойства и поясним его. Итак, объявление любого свойства начинается с указания ключевого слова &amp;lt;tt&amp;gt;'''property'''&amp;lt;/tt&amp;gt;, после которого идет [[идентификатор]] типа свойства. Тип может быть опущен, тогда для свойства будет определен [[Переменные#Нетипированные (динамические) переменные|динамический тип]]. Затем указывается идентификатор имени свойства. &lt;br /&gt;
&lt;br /&gt;
Оставшаяся часть зависит от того, какое свойство объявляется:&lt;br /&gt;
&lt;br /&gt;
* Если объявляется свойство на чтение, то указывается ключевое слово &amp;lt;tt&amp;gt;'''read'''&amp;lt;/tt&amp;gt;, после которого идет либо идентификатор имени поля, которое нужно читать, либо имя метода, который должен использоваться как ''аксессор''. В роли аксессора может выступать метод, не принимающий параметров и возвращающий некоторое значение, которое будет возвращаться как значение свойства.&lt;br /&gt;
* Если объявляется свойство на запись, то указывается, соответственно ключевое слово &amp;lt;tt&amp;gt;'''write'''&amp;lt;/tt&amp;gt; после которого идет либо имя поля, которое нужно записывать, либо имя метода, который должен использоваться как ''мутатор''. В качестве мутатора может выступать метод, принимающий один параметр. Возвращаемое значение игнорируется, так что оно может быть любым.&lt;br /&gt;
* Если объявляется свойство, доступное как на чтение, так и на запись, то указываются обе части, причем первой идет часть чтения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' Если тип свойства указан явно, то в зависимости от типа поля либо типа возвращаемого значения аксессора, может быть выполнена операция [[Приведение типов|приведения типов]]. Разумеется, если тип поля или результат аксессора неприводим к указанному типу свойства, то будет выдано сообщение об ошибке. Аналогичная ситуация обстоит и с параметром мутатора.&lt;br /&gt;
&lt;br /&gt;
Кратко, синтаксис объявления свойства можно описать в стиле справки к командам оболочки:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
property [тип] &amp;lt;имя&amp;gt; [read &amp;lt;аксессор|поле&amp;gt;] [write &amp;lt;мутатор|поле&amp;gt;];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Расширения ==&lt;br /&gt;
&lt;br /&gt;
Иногда бывает необходимо расширить функциональность некоторого существующего класса без порождения дочернего класса. Это может быть необходимо в тех случаях, когда исходный класс уже используется в коде программы и порождение нового класса нарушило бы спецификацию на интерфейс, либо потребовало значительных изменений в исходных текстах программы. В таких случаях целесообразно применять т. н. ''расширения классов''. Синтаксически, конструкция расширения практически не отличается от конструкции объявления класса, однако методы и свойства перечисленные в нем, дополняются к исходному классу, то есть наследования не происходит.&lt;br /&gt;
&lt;br /&gt;
Как правило, расширения применяются к классам [[Стандартной библиотека Gide|стандартной библиотеки]], либо к [[unmanaged код|неуправляемым классам]].&lt;br /&gt;
&lt;br /&gt;
В качестве примера приведем код, расширяющий функциональность класса &amp;lt;tt&amp;gt;[[Стандартные типы данных#Целые числа|int]]&amp;lt;/tt&amp;gt; с помощью свойства &amp;lt;tt&amp;gt;factorial&amp;lt;/tt&amp;gt;. Расширения объявляются путем указания ключевого слова &amp;lt;tt&amp;gt;'''extend'''&amp;lt;/tt&amp;gt;, после которого указывается [[идентификатор]] имени класса, который следует расширить. Затем идет тело расширения, такое же как при описании классов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
package intmod_fact;&lt;br /&gt;
import std;&lt;br /&gt;
external console_stream STDOUT;&lt;br /&gt;
function void println(const string s) { STDOUT.print(s + &amp;quot;\n&amp;quot;); }&lt;br /&gt;
&lt;br /&gt;
extend int {&lt;br /&gt;
    const function ubigint GetFactorial() {&lt;br /&gt;
        var ubigint result = 1, int x;&lt;br /&gt;
        for (x = this; x &amp;gt; 1; --x)&lt;br /&gt;
            result *= x;&lt;br /&gt;
        return result;&lt;br /&gt;
    }&lt;br /&gt;
    property ubigint factorial read GetFactorial;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
export function main() {&lt;br /&gt;
    println(&amp;quot;Factorial of 10 is &amp;quot; + 10.factorial);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;6-14: Мы объявляем расширение класса &amp;lt;tt&amp;gt;[[Стандартные типы данных#Целые числа|int]]&amp;lt;/tt&amp;gt;, реализованного в [[Стандартная библиотека gide|стандартной библиотеке]]. Добавляется частный метод &amp;lt;tt&amp;gt;GetFactorial()&amp;lt;/tt&amp;gt;, и свойство &amp;lt;tt&amp;gt;factorial&amp;lt;/tt&amp;gt;, связанное с методом. Как видно из названия, метод рассчитывает факториал числа, которое содержится в объекте. В данном контексте, специальная переменная ''this'' имеет тип &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt; и ссылается на сам объект. Таким образом, для числа 10 переменная ''this'' будет равна 10.&lt;br /&gt;
&lt;br /&gt;
;17: Здесь мы видим применение расширения в действии. Константа 10 на момент компиляции преобразуется в [[Константы#Константные объекты|константный объект]] класса &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;, который подобно любому другому объекту этого же класса будет иметь свойство &amp;lt;tt&amp;gt;factorial&amp;lt;/tt&amp;gt;, которое мы и используем. При попытке чтения из этого свойства будет вызван метод &amp;lt;tt&amp;gt;GetFactorial()&amp;lt;/tt&amp;gt;, результат выполнения которого возвращается как значение свойства, то есть как факториал числа. &amp;lt;!--Его мы вызываем с помощью специального синтаксиса, для передачи блока в качестве [[Функции#Аргументы|параметра функции]]. При этом, сам блок указывается прямо в коде вызова функции. Тело блока состоит из одного вызова функции, выводящей текущее число в стандартный поток вывода. --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
: Обратите внимание, что функция &amp;lt;tt&amp;gt;println()&amp;lt;/tt&amp;gt;, принимает в качестве параметра [[Стандартные типы данных#Строки|строку]], в то время как тип свойства определен как &amp;lt;tt&amp;gt;[[Стандартные типы данных#Целые числа|ubigint]]&amp;lt;/tt&amp;gt;. В этом нет ничего странного, потому что класс &amp;lt;tt&amp;gt;ubigint&amp;lt;/tt&amp;gt; имеет [[Типы операторов#Операторы приведения типов|оператор приведения типа]] к классу &amp;lt;tt&amp;gt;[[Стандартные типы данных#Строки|string]]&amp;lt;/tt&amp;gt;, который вызывается компилятором автоматически. Таким образом, при вычислении значения выражения в скобках, сперва значение факториала ''приводится'' к типу строки, которая складываясь со строкой слева от оператора &amp;lt;tt&amp;gt;+&amp;lt;/tt&amp;gt; передается в качестве параметра функции.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' При работе с расширениями существует одно важное ограничение. Расширять классы можно только методами и свойствами, но не полями. Это связано с внутренней организацией языка К++ и виртуальной машины. Дополнительно стоит отметить, что методы объявленные в расширении будут перекрывать соответствующие им методы класса (имеется в виду ситуация когда имена и наборы параметров полностью совпадают). Важно понимать, что такое перекрытие не является объявлением виртуального метода — происходит именно замещение старого метода новым. &lt;br /&gt;
&lt;br /&gt;
== Смотри также ==&lt;/div&gt;</summary>
		<author><name>KroTozeR</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%9A%D0%BB%D0%B0%D1%81%D1%81%D1%8B_%D0%B8_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B</id>
		<title>Классы и объекты</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%9A%D0%BB%D0%B0%D1%81%D1%81%D1%8B_%D0%B8_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B"/>
				<updated>2007-10-05T11:29:53Z</updated>
		
		<summary type="html">&lt;p&gt;KroTozeR: /* Методы */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== История развития ООП ==&lt;br /&gt;
&lt;br /&gt;
Для того чтобы понять, что же такое классы и объекты, сперва необходимо проследить историю развития программирования. А конкретнее, историю возникновения концепции ООП. Автор верит, что знание истории возникновения тех или иных мыслей и идей может помочь читателю осознать необходимость нововведений, и главное — их преимуществ перед существовавшими в то время решениями.&lt;br /&gt;
&lt;br /&gt;
=== Возникновение языков программирования ===&lt;br /&gt;
&lt;br /&gt;
На заре зарождения вычислительных машин их приходилось программировать поистине &amp;quot;вручную&amp;quot;. Все, что было в руках  программиста это пульт управления ЭВМ. На шестнадцатеричной клавиатуре (а еще раньше на пульте с тумблерами) программист задавал некоторый адрес ячейки памяти, затем он мог либо выполнить операцию чтения — тогда на табло появлялись цифры, соответствующие значению ячейки памяти, либо операцию записи — при этом, по указанному адресу записывалось значение, набранное на клавиатуре данных. Затем, программист переходил к следующей ячейке, и так повторялось до тех пор, пока в память ЭВМ не была внесена вся программа. На программистах (точнее, на операторах ЭВМ) лежала огромная ответственность! Одна ошибка, один неверно установленный переключатель или одна пропущенная команда неминуемо вели к ошибкам в работе программы, а, следовательно, и к ошибкам в расчетах. Могли потребоваться недели, и даже месяцы на поиск этой ошибки и на ее исправление! Естественно, ни о каких языках программирования тогда не могло идти и речи.&lt;br /&gt;
&lt;br /&gt;
=== Появление ассемблера ===&lt;br /&gt;
&lt;br /&gt;
Впоследствии, программисты смекнули, что команды можно записывать в виде мнемонических обозначений или мнемоник — то, что раньше применялось только для удобства записи на бумаге — было стандартизировано и приспособлено как ''язык'' общения человека и ЭВМ. Так появился первый язык программирования — ''язык ассемблера''. Конечно, языком его можно назвать с некоторой натяжкой, ведь он не обеспечивал и десятой доли тех возможностей (вроде автоматического разбора арифметических выражений), которые мы привыкли ассоциировать с языками программирования. Тем не менее, ассемблер выполнял свою главную и основную функцию — избавлял программиста от необходимости работать с памятью (и адресами) напрямую. Вместо этого, программист записывал свои команды в стандартной форме, понятной ЭВМ. Далее выполнялась программа ''транслятор'', которая преобразовывала исходный текст программы в поток машинных команд, которые уже можно исполнять.&lt;br /&gt;
&lt;br /&gt;
=== Концепция языка высокого уровня ===&lt;br /&gt;
&lt;br /&gt;
...С увеличением сложности программ, программировать на ассемблере становилось все сложнее и сложнее.  Ввиду естественных ограничений человеческой памяти и внимания, написание программ и их отладка стали настолько сложными, что люди всерьез подошли к рассмотрению идеи языка высокого уровня — некоторой системы обозначений и абстрактных команд, которая позволила бы записывать программы в абстрактной форме, не заботясь о том, как располагать в памяти код и данные, как их структурировать и т. д. Всю эту работу брал на себя компилятор. Кроме того, он обеспечивал программиста удобным способом записи математических выражений — в естественной форме. При этом, компилятор сам &amp;quot;разворачивал&amp;quot; эти выражения в наборы инструкций ассемблера, попутно подставляя значения констант и адреса переменных. Это дало возможность программистам записывать формулы вычислений в натуральном виде, что уменьшало трудозатраты, ускоряло написание программ и уменьшало вероятность ошибок. Тем не менее, многие авторитеты того времени очень негативно отзывались о языках высокого уровня. В то время языки были довольно несовершенными и генерировали &amp;quot;ужасный&amp;quot; с точки зрения программистов код. Код был не оптимален, занимал огромное по тем временам количество памяти и работал медленнее, чем та же программа, написанная на ассемблере. Смешно сказать, но в то время многие не верили в то, что будущее за ЯП высокого уровня; их считали не более чем игрушкой для &amp;quot;чайников&amp;quot;, возжелавших вообразить себя настоящими программистами. &lt;br /&gt;
&lt;br /&gt;
Но время шло, количество приверженцев нового подхода постоянно увеличивалось. Сами же компиляторы становились все более мощными и генерировали все более компактный и оптимальный код. Дошло до того, что компилятор с оптимизатором в некоторых случаях генерировал код, более качественный, чем это делал программист. С этого момента ЯП высокого уровня заняли свое место в истории и в инструментарии любого разработчика.&lt;br /&gt;
&lt;br /&gt;
=== Структурное программирование ===&lt;br /&gt;
&lt;br /&gt;
С развитием языков программирования появились новые концепции и новые парадигмы программирования. От линейного моноблочного программирования, при котором программа писалась единым &amp;quot;куском&amp;quot; от начала до конца, перешли к программам модульным и структурным. При них программа представляла уже совокупность процедур (функций), которые вызывали друг друга в ходе работы программы. Процедуры представляли собой подпрограммы, решающие отдельные частные задачи. При этом код получался более читаемым, и облегчалась его отладка. &lt;br /&gt;
&lt;br /&gt;
Опять же, в ходе усложнения решаемых задач и, вследствие этого, увеличения количества переменных с которыми приходилось работать программисту, возникла идея группировки некоторых переменных в группы или структуры. Структуры формировались по назначению и содержали в себе переменные, имеющие отношение к одной и той же сущности. Это значительно повысило читаемость программ и уменьшило количество ошибок в них.&lt;br /&gt;
&lt;br /&gt;
=== Объектно-ориентированное программирование ===&lt;br /&gt;
&lt;br /&gt;
Ну и наконец, одна светлая голова додумалась до мысли: &amp;quot;а что если в структурах группировать не только переменные, но и сами процедуры которые должны работать с этими переменными?&amp;quot;. В результате получилось то, что мы сейчас называем классом — то есть, некоторая обособленная функциональная сущность, которая сама хранит свои данные, а главное сама умеет их обрабатывать. Теперь программисту не нужно помнить, какая из процедур отвечает за некоторое действие над такими-то переменными — он просто берет объект и работает с ним. Все что происходит с объектом внутри — это его личное дело.&lt;br /&gt;
&lt;br /&gt;
Последним шагом к современному пониманию программ явились концепции [http://ru.wikipedia.org/wiki/Полиморфизм_(программирование) полиморфизма], [http://ru.wikipedia.org/wiki/Инкапсуляция_(программирование) инкапсуляции] и [http://ru.wikipedia.org/wiki/Наследование_(программирование) наследования]. Не будем пока углубляться в суть этих понятий, отметим только, что их введение сформировало современное понимание объектно-ориентированного программирования.&lt;br /&gt;
&lt;br /&gt;
При написании программы на объектно-ориентированном языке, программист строит математическую модель взаимодействия различных сущностей. Каждая из сущностей это свой мир, у которого есть свои законы и особенности. При этом сущности могут быть как конкретные, вроде &amp;quot;сетевой интерфейс&amp;quot; или &amp;quot;файл&amp;quot;, так и совершенно абстрактные, например &amp;quot;отношение&amp;quot; или &amp;quot;ошибка&amp;quot;. Программист описывает каждую из сущностей в отдельности, обособлено от остальных. Вся необходимая для работы информация хранится внутри, а для взаимодействия с внешним миром предусмотрен ''интерфейс'' — некоторая совокупность ''свойств'' данной сущности (отражающих ее внутреннее состояние) и способов взаимодействия с ней — ''методов''.&lt;br /&gt;
&lt;br /&gt;
В ходе работы программы сущности могут взаимодействовать, читая и записывая свойства и вызывая методы друг друга, использовать друг друга как подсистемы, порождать новые сущности и т. д. Получается, что при написании программы, программист переносит свое внутреннее представление того как он видит эту программу, то из чего она состоит и как отдельные ее части взаимодействуют. Теперь не приходится адаптировать свое понимание проблемы к конкретным инструментальным средствам и возможностям языка программирования (конечно, это все же происходит, но уже гораздо менее заметно).&lt;br /&gt;
&lt;br /&gt;
В терминах современных языков программирования такие сущности называются ''классами'', в смысле ''классами сущностей''. А отдельные представители этих классов называются ''экземплярами'', ''инстанциями'' (на английский манер) или ''объектами''. Более подробно, различие между классами и объектами будет рассмотрено ниже.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Итак, любой современный объектно-ориентированный язык оперирует понятиями классов и объектов. Точно такой же подход нашел свое применение в нашей виртуальной машине. Основой всей платформы Gide является объектно-ориентированный принцип. Причем, в этом смысле она является более объектно-ориентированной, нежели традиционные ЯП вроде C++. В C++ существуют понятия элементарных типов. Это сделано в целях производительности и было продиктовано архитектурой самого языка. В классических языках программирования, элементарные типы, так или иначе, отражают сущности из &amp;quot;реального мира&amp;quot;. Например, целочисленные типы int и short соответствуют 32х и 16ти разрядным регистрам процессора, указатели и строки соответствуют представлению данных в памяти и т. д. В Gide это не так. Все с чем оперирует виртуальная машина — это объекты. Соответственно, не существует понятия элементарных типов (просто нет критерия, который бы позволил отделить одно от другого). &lt;br /&gt;
&lt;br /&gt;
Язык K++ в полной мере наследует идеологию Gide. Скажем, для него нет отличия между типом &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt; (целое число) и некоторым пользовательским классом &amp;lt;tt&amp;gt;MyWeirdClass&amp;lt;/tt&amp;gt;: везде, где можно использовать &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;, можно использовать &amp;lt;tt&amp;gt;MyWeirdClass&amp;lt;/tt&amp;gt; и наоборот. Более того, это позволяет работать с системными классами так же, как с пользовательскими! Например, ничто не мешает унаследовать свой класс от класса &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;, равно как ничто не мешает определить математические операторы для класса &amp;lt;tt&amp;gt;MyWeirdClass&amp;lt;/tt&amp;gt; и использовать объекты этого класса в арифметических выражениях. При этом изменится логика работы всего языка. К примеру, после добавления некоторого метода к классу int можно будет вызывать методы у всех его экземпляров, даже тех, что представлены числовыми константами внутри самого языка!&lt;br /&gt;
&lt;br /&gt;
== Понятие класса ==&lt;br /&gt;
&lt;br /&gt;
Что такое ''класс'' проще всего объяснить на примерах. Представьте, что вас спрашивают &amp;quot;что такое яблоко?&amp;quot;. Скорее всего, вы ответите что-то вроде: &amp;quot;яблоки, это вкусные плоды, растущие на деревьях — яблонях; они бывают разных цветов и размеров&amp;quot;. Заметьте, что когда мы описываем ''яблоки как понятие'', мы не имеем в виду некоторый конкретный объект, а скорее описываем наше обобщенное представление о них. Если же вас попросят описать совершенно конкретное яблоко, лежащее на блюдечке перед вами, вы будете говорить о нем по другому: &amp;quot;это яблоко, оно красное, сочное, судя по всему спелое. С черенком, на котором остался листик, и маленькой червоточинкой&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Разница заключается в том, что когда вы говорили ''о яблоках'', вы описывали свое представление яблок, как ''класса'' объектов. Когда вы описывали ''яблоко'', то вы имели в виду конкретный ''экземпляр'', или ''объект''. Говоря о классе, вы можете описать только те свойства, что принадлежат всем яблокам; когда же вы описываете объект, то в первую очередь имеете в виду его индивидуальные особенности (свойства). Тем не менее, описание объекта начинается с упоминания его класса (&amp;quot;это яблоко,...&amp;quot;), а затем уже свойств объекта (ведь &amp;quot;сочным и спелым&amp;quot; может быть и апельсин). Это важная особенность объектно-ориентированного подхода. &lt;br /&gt;
&lt;br /&gt;
Другой пример: если вас попросить &amp;quot;представьте дерево&amp;quot;, то вы либо представите некоторое совершенно абстрактное, усредненное дерево, либо попросите уточнить, какое именно дерево имеется в виду. Ваше сознание из имеющейся информации смогло уяснить только самые общие сведения о классе. Но этой информации не достаточно, для более детального описания. Это тоже важно, поскольку в этом простом примере кроется сущность механизма наследования — постепенного уточнения классами-потомками общих черт своих предков. Таким образом, и яблоня, и груша — деревья. Но яблони отличаются от груш. Получается, что классы ''яблони'' и ''груши'' имеют общего предка — класс ''дерево''.&lt;br /&gt;
&lt;br /&gt;
Таким образом, понятия классов и объектов это не математическая абстракция, а скорее часть нашего восприятия мира, того как мы мыслим.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из примеров выше мы смогли уяснить следующее:&lt;br /&gt;
&lt;br /&gt;
* Классы, это некоторые абстрактные сущности, задающие общие черты своих объектов&lt;br /&gt;
* Все объекты одного класса похожи друг на друга, но имеют некоторые индивидуальные особенности&lt;br /&gt;
* Классы могут наследоваться, расширяя набор свойств класса родителя своими собственными&lt;br /&gt;
&lt;br /&gt;
Перейдем теперь ближе к основной теме нашего повествования, а именно языку К++:&lt;br /&gt;
&lt;br /&gt;
С точки зрения языка, ''класс'' представляет собой набор следующих элементов:&lt;br /&gt;
* ''полей'', т.е. переменных, хранящих индивидуальные особенности объектов, &lt;br /&gt;
* ''методов'', т.е. функций, определяющих поведение данного объекта;&lt;br /&gt;
* ''свойств'', определяющих взаимодействие других объектов с объектами данного класса.&lt;br /&gt;
&lt;br /&gt;
''Поля'' — это переменные, которые относятся к некоторому конкретному экземпляру нашего класса. Каждый экземпляр имеет свою копию набора переменных, таким образом, они могут хранить свое состояние (например, показатель &amp;quot;спелости&amp;quot;, в примере с яблоками). Эти переменные доступны только самому классу, доступ извне для них запрещен. Для того чтобы частично разрешить этот доступ, применяются ''свойства''. Сами свойства будут описаны позже, здесь стоит отметить только то, что свойство может быть доступно &amp;quot;только на чтение&amp;quot;, &amp;quot;только на запись&amp;quot; или &amp;quot;и на чтение и на запись&amp;quot;. Свойство может быть связано либо с некоторым полем, либо с методом. Например, если свойство доступно &amp;quot;только на чтение&amp;quot; то его можно использовать для получения значения, но не для его записи (то есть, такое свойство не может фигурировать в качестве [[lvalue]]).&lt;br /&gt;
&lt;br /&gt;
''Методы'' — это тот самый, связанный с данными код (вспомните [[Классы и объекты#История развития ООП|историю ООП]]) который, естественно, может работать с переменными объекта (то есть с полями) и служит для описания поведения данного класса объектов.&lt;br /&gt;
&lt;br /&gt;
Класс может иметь одного или нескольких родителей (опять же, подробнее об этом см. ниже)&lt;br /&gt;
&lt;br /&gt;
Методы и свойства класса могут находиться в различных областях видимости. Это обеспечивается с помощью [[Спецификаторы доступа|спецификаторов доступа]]:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''private'''&amp;lt;/tt&amp;gt; — Частная собственность! Видимость только внутри методов данного класса&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''protected'''&amp;lt;/tt&amp;gt; — &amp;quot;Семейная реликвия&amp;quot;, доступ внутри методов данного класса и всех его дочерних классов&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''public'''&amp;lt;/tt&amp;gt; — видимость и доступ для всех&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' По умолчанию методы имеют видимость &amp;lt;tt&amp;gt;'''private'''&amp;lt;/tt&amp;gt;, в то время как свойства — &amp;lt;tt&amp;gt;'''public'''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Приведем, наконец, пример объявления класса:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
class MyWeirdClass {&lt;br /&gt;
    var m_x = 0;  // поле m_x, изначально проинициализированное нулем&lt;br /&gt;
    const m_y = 1; // поле-константа m_y&lt;br /&gt;
&lt;br /&gt;
    // методы класса&lt;br /&gt;
    public const function int get_mul() { return m_x * m_y; }&lt;br /&gt;
    public function void set_mul(int x) { m_x = x / m_y; }&lt;br /&gt;
&lt;br /&gt;
    // свойство класса&lt;br /&gt;
    public property mul read get_mul write set_mul;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;1: Как у любого нормального разумного существа, у класса есть &amp;quot;голова&amp;quot; и &amp;quot;тело&amp;quot;. Ключевое слово &amp;lt;tt&amp;gt;'''class'''&amp;lt;/tt&amp;gt; начинает объявление класса. Далее за ним следует [[идентификатор]] имени класса, после чего идет тело класса.&lt;br /&gt;
&lt;br /&gt;
;3-4: Здесь мы видим объявление двух полей класса — переменной ''m_x'' и константы ''m_y'', которые, подобно обычным переменным инициализируются тут же, на месте объявления (камень в огород C++). Зачем нужны поля-константы, описано в главе [[Константы]].  &lt;br /&gt;
&lt;br /&gt;
;7-8: Для доступа к состоянию объекта, определены два метода: ''аксессор'' &amp;lt;tt&amp;gt;get_mul()&amp;lt;/tt&amp;gt; и ''мутатор'' &amp;lt;tt&amp;gt;set_mul()&amp;lt;/tt&amp;gt;. Подобные конструкции применяются настолько часто, что им были даны специальные имена. Как видно из названия, первый метод дает доступ к значению, второй изменяет или мутирует его.&lt;br /&gt;
&lt;br /&gt;
;11: Завершается объявление класса объявлением свойства ''mul'', которое связывается с аксессором и мутатором. Думаю, читатель уже догадался, что это свойство типа &amp;quot;чтение и запись&amp;quot;. Таким образом, при обращении к свойству на чтение, будет вызван аксессор, а результат его выполнения будет возвращен в качестве значения свойства. И, наоборот, при попытке записать в свойство некоторое значение, будет вызван мутатор, в качестве аргумента которому будет передано это самое значение, а уж сам мутатор позаботится о том, чтобы оно было &amp;quot;доставлено по адресу&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
: '''Примечание:''' Зачем нужны такие сложности, и зачем дублировать вроде бы одинаковый функционал, будет описано ниже.&lt;br /&gt;
&lt;br /&gt;
== Понятие объекта ==&lt;br /&gt;
&lt;br /&gt;
Собственно, понятие объекта уже много раз было затронуто выше по повествованию. Поэтому здесь приведем лишь небольшое определение: Под ''объектом'' подразумевается экземпляр того или иного класса, т.е. некоторая сущность, поведение которой задается соответствующим классом.&lt;br /&gt;
&lt;br /&gt;
Для создания объекта того или иного класса служит оператор &amp;lt;tt&amp;gt;'''new'''&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
    var myWeirdObject = new MyWeirdClass;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь мы видим типичную конструкцию объявления переменной, однако в инициализаторе переменной находится всего один оператор, за которым следует [[идентификатор]] имени класса, экземпляр которого мы хотим создать.&lt;br /&gt;
&lt;br /&gt;
== Наследование ==&lt;br /&gt;
&lt;br /&gt;
Под ''наследованием'' классов понимается механизм такого создания (объявления) класса, при котором он расширяет функционал одного или нескольких уже существующих классов (родителей). Вспомните пример с деревьями. Когда мы говорим, что класс ''яблоня'' наследуется от класса ''дерево'' — это значит что ''яблоня'' унаследует все свойства своего класса-родителя, некоторые из которых он может изменить, ну и дополнить своими собственными свойствами. Опыт нам подсказывает, что у любого дерева есть листья (для простоты не будем вспоминать про хвойные), однако не любое дерево плодоносит яблоками. Если же рассмотреть сами яблоки, то можно сказать, что класс ''яблоко'' унаследован от класса ''фрукт'', который определяет что фрукты (и соответственно яблоки) должны расти на деревьях.&lt;br /&gt;
&lt;br /&gt;
Таким образом, наследование гарантирует, что к дочерним классам применимы все операции, доступные в родительском классе: любой алгоритм, работающий с объектами родительского класса, может работать с объектами его дочерних классов. &lt;br /&gt;
&lt;br /&gt;
Для задания наследования, в объявлении класса следует указать ключевое слово &amp;lt;tt&amp;gt;'''extends'''&amp;lt;/tt&amp;gt;,  за которым необходимо перечислить список идентификаторов классов-родителей, разделяя их запятыми:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
// коробка&lt;br /&gt;
class Box { &lt;br /&gt;
    // из чего сделана коробка?&lt;br /&gt;
    public const function string material() { return &amp;quot;Картон&amp;quot;; }&lt;br /&gt;
&lt;br /&gt;
    // что в коробке?&lt;br /&gt;
    public const function string contents() { return &amp;quot;Пусто&amp;quot;; }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// коробка с картошкой&lt;br /&gt;
class BoxWithPotatoes extends Box { &lt;br /&gt;
    public const function string contents() { return &amp;quot;Картошка&amp;quot;; }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function OutputBox(const Box b) {&lt;br /&gt;
    STDOUT.print(&amp;quot;Материал: &amp;quot; + b.material() + &amp;quot;, содержит: &amp;quot; + b.contents() + &amp;quot;\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function main() {&lt;br /&gt;
    var b1 = new Box;&lt;br /&gt;
    var b2 = new BoxWithPotatoes;&lt;br /&gt;
    OutputBox(b1); // Материал: Картон, содержит: Пусто&lt;br /&gt;
    OutputBox(b2); // Материал: Картон, содержит: Картошка&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;2-7: В этом примере мы создаем класс &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt;, который представляет собой некоторую коробку. Мы определяем ее свойства, такие как ''материал'' и ''содержимое''.&lt;br /&gt;
&lt;br /&gt;
;10-12: Далее мы определяем класс &amp;lt;tt&amp;gt;BoxWithPotatoes&amp;lt;/tt&amp;gt; (''коробка с картошкой''), который наследуется от класса &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt;, и тем самым заимствует свойства материала и содержимого, но первое он переопределяет (в случае методов это называется ''перекрытием'') собственным методом.&lt;br /&gt;
&lt;br /&gt;
;14-16: Мы определяем некоторую [[Функции|функцию]] для работы с нашими классами, которая будет отображать их состояние. Заметьте, что в качестве [[Функции#Аргументы|аргумента функции]] передается экземпляр класса &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt;, то есть класса-родителя. При этом мы предполагаем, что любой класс, унаследованный от базового класса, будет обладать необходимым нам интерфейсом, а именно методами получения информации о свойствах (аксессорами мы их не называем, потому что они не связаны с конкретным полем; это было бы неверно).&lt;br /&gt;
&lt;br /&gt;
;18-23: Объявляется функция &amp;lt;tt&amp;gt;main()&amp;lt;/tt&amp;gt;, внутри которой и происходит самое интересное. Сначала мы создаем два экземпляра ''b1'' и ''b2'' классов &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt; и &amp;lt;tt&amp;gt;BoxWithPotatoes&amp;lt;/tt&amp;gt; соответственно. А затем, вызываем вышеописанную функцию &amp;lt;tt&amp;gt;OutputBox()&amp;lt;/tt&amp;gt;, которая отображает содержимое. Вывод в терминал (написан в комментарии к вызову) показывает, как это все работает.&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' при использовании множественного наследования существует одно серьезное ограничение: его нельзя применять для наследования от классов стандартной библиотеки. Это ограничение связано с архитектурой платформы Gide. Однако его можно обойти с помощью создания [[Класс-обертка|классов-оберток]] для системного класса, с последующим наследованием от него нового класса.&lt;br /&gt;
&lt;br /&gt;
== Методы ==&lt;br /&gt;
&lt;br /&gt;
''Метод'' — это некоторый код, связанный с объектом и управляющий его поведением. Управление может заключаться в изменении переменных состояния объекта (полей), либо выполнением некоторых операций над ними.&lt;br /&gt;
&lt;br /&gt;
При объявлении метода могут быть указаны следующие ключевые слова, в указанном порядке:&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''private'''&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;'''protected'''&amp;lt;/tt&amp;gt; или &amp;lt;tt&amp;gt;'''public'''&amp;lt;/tt&amp;gt; — определяют область видимости метода&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''static'''&amp;lt;/tt&amp;gt; — указывает, что метод является ''статическим'' (см. ниже)&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''const'''&amp;lt;/tt&amp;gt; — метод не изменяет объект&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''function'''&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;'''operator'''&amp;lt;/tt&amp;gt; или &amp;lt;tt&amp;gt;'''constructor'''&amp;lt;/tt&amp;gt; указывает, что объявляется: ''метод'', ''[[Операторы|оператор]]'' или ''конструктор'' (см. ниже)&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''const'''&amp;lt;/tt&amp;gt; — метод возвращает результат, который нельзя изменять&lt;br /&gt;
&lt;br /&gt;
После этого указывается тип, возвращаемый методом. Если он опущен — возвращается [[Переменные#Нетипированные (динамические) переменные|динамическая переменная]]; если вместо типа указано ключевое слово &amp;lt;tt&amp;gt;'''void'''&amp;lt;/tt&amp;gt; — метод не возвращает результата. Следом за типом идет имя метода, затем — перечисление [[Функции#Аргументы|аргументов]] в скобках. Подробнее об объявлении функций и передаче параметров, можно прочитать в главе [[Функции]].&lt;br /&gt;
&lt;br /&gt;
Тело метода может быть объявлено как непосредственно в теле класса, так и вынесено за его пределы, например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
class MyClass {&lt;br /&gt;
    public const function string F1() { return &amp;quot;smth&amp;quot;; }&lt;br /&gt;
    public const function string F2();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function string MyClass::F2() {&lt;br /&gt;
    return F1();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;6: При вынесении функции за пределы класса, имя соответствующего метода предваряется именем класса, из которого он был вынесен; имена отделяются друг от друга символом &amp;quot;двойное двоеточие&amp;quot; ( &amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt; ); дополнительно — в заголовке вынесенной функции необходимо указать тип возвращаемого значения и параметры функции, все остальные ключевые слова указывать не обязательно.&lt;br /&gt;
&lt;br /&gt;
;7: В теле метода доступны все поля, методы и свойства данного класса и его предков. Например, в коде приведенном выше, метод &amp;lt;tt&amp;gt;F2()&amp;lt;/tt&amp;gt; вызывает метод &amp;lt;tt&amp;gt;F1()&amp;lt;/tt&amp;gt; для того же объекта.&lt;br /&gt;
&lt;br /&gt;
=== Статические методы ===&lt;br /&gt;
&lt;br /&gt;
''Статический метод класса'' — это метод, относящийся к данному классу, но не объекту этого класса. Т.е. это некоторая вспомогательная для данного класса функция.&lt;br /&gt;
&lt;br /&gt;
При объявлении статического метода нужно указать ключевое слово &amp;lt;tt&amp;gt;'''static'''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В теле статического метода нет возможности напрямую обращаться к другим методам данного класса, т.к. статическому методу недоступен объект класса. Фактически, единственным отличием статического метода от обычной функции является то, что такой метод может обращаться к защищенным полям и методам класса некоторого другого объекта. Подобный подход широко применяется при написании ''конструкторов'' (см. ниже).&lt;br /&gt;
&lt;br /&gt;
Пример:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
class MyClass {&lt;br /&gt;
    public static function string Info() { return &amp;quot;Я MyClass!&amp;quot;; }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function f() {&lt;br /&gt;
    // Вызов статического метода:&lt;br /&gt;
    var myClassInfo = MyClass.Info();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Конструкторы ===&lt;br /&gt;
&lt;br /&gt;
В ходе написания программы часто приходится создавать новые объекты. При этом объекту требуется установить некоторое начальное состояние. Разумеется, это выполняется либо путем написания инициализаторов соответствующих полей, либо значения полям присваиваются явным образом. Но что делать, если объект может иметь несколько начальных состояний? То есть, в зависимости от некоторых условий, одним и тем же полям объекта могут быть присвоены различные наборы значений. Тут уже одними инициализаторами не обойтись. Присваивать значения можно прямо в коде программы, однако это не очень красивое решение, поскольку один и тот же объект может создаваться в нескольких местах программы и придется копировать один и тот же участок кода, инициализирующий поля объекта. Недостаток этого подхода в том, что при большом количестве полей, программист может забыть проинициализировать некаторе поле, либо при изменении условий инициализации он может изменить их только в одном месте программы, забыв, что объект может создаваться и в других местах. Более разумным является подход, при котором программист пишет функцию, инициализирующую поля объекта. При этом весь код собирается в одном месте и вероятность ошибок значительно понижается. &lt;br /&gt;
&lt;br /&gt;
Конструкторы развивают эту идею, дополняя код инициализации полей кодом создания самого экземпляра объекта. То есть, в конструкторе собирается весь код, относящийся к созданию инстанции класса. Итак, ''конструктор класса'' — это специальный метод, инициализирующий объект класса. С точки зрения языка, конструктор — это статический метод класса, возвращающий экземпляр данного класса.&lt;br /&gt;
&lt;br /&gt;
Таким образом, следующие объявления в рамках класса эквивалентны:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
public constructor Create();&lt;br /&gt;
public static MyClass Create();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тело конструктора чаще всего выглядит следующим образом: сначала создается экземпляр класса при помощи оператора &amp;lt;tt&amp;gt;'''new'''&amp;lt;/tt&amp;gt;, затем производятся некоторые действия, инициализующие этот объект, и, наконец, этот объект возвращается в качестве результата. &lt;br /&gt;
&lt;br /&gt;
В качестве примера приведем пример реализации некоторого абстрактного класса &amp;lt;tt&amp;gt;MyStream&amp;lt;/tt&amp;gt;, использующего системную реализацию класса &amp;lt;tt&amp;gt;stream&amp;lt;/tt&amp;gt;, и определяющую собственный конструктор:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
class MyStream {&lt;br /&gt;
    var string m_URL;&lt;br /&gt;
    var stream m_Stream;&lt;br /&gt;
public:&lt;br /&gt;
    static const MODE_READ = 1;&lt;br /&gt;
    static const MODE_WRITE = 2;&lt;br /&gt;
    constructor open(const string url, int mode) {&lt;br /&gt;
        var self = new MyStream;&lt;br /&gt;
        self.m_Stream.open(url, mode);&lt;br /&gt;
        self.m_URL = url;&lt;br /&gt;
        return self;&lt;br /&gt;
    }&lt;br /&gt;
    // прочие методы (опущены для краткости)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;2-3: Объявляются поля ''m_URL'' и ''m_Stream'' нашего класса, которые будут инициализироваться в конструкторе. &lt;br /&gt;
&lt;br /&gt;
;5-6: В публичной области класса объявляются статические константы ''MODE_READ'' и ''MODE_WRITE'', которые задают желаемый режим доступа к открываемому потоку. Это единственный случай, когда поле класса доступно на прямой доступ извне.&lt;br /&gt;
&lt;br /&gt;
;7: Объявляется конструктор &amp;lt;tt&amp;gt;open()&amp;lt;/tt&amp;gt;, принимающий в качестве параметров [[URL]] ресурса который требуется открыть и число, задающее с помощью вышеописанных констант режим доступа к потоку. В теле конструктора мы создаем инстанцию ''self'' нашего класса. Затем производится попытка открытия потока ''m_Stream'': если операция пройдет успешно, то происходит инициализация оставшегося поля ''m_URL'' и выход из конструктора с возвратом созданной инстанции; если же операция открытия потока провалится, то будет сгенерировано ''[[Обработка исключений|исключение]]'' и выполнение конструктора прекратится (управление будет передано &amp;quot;наверх&amp;quot;, вызывающему коду).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Использовать наш класс можно примерно так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;var data = MyStream.open(&amp;quot;http://www.deeptown.org/index.html&amp;quot;, MyStream.MODE_READ);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на второй параметр функции, где мы передаем константу ''MODE_READ'', объявленную внутри самого класса. Подобный подход, когда константы, используемые при работе с классом, инкапсулируются в тело класса, помогает сконцентрировать код в одном месте и избежать многих ошибок. В результате повышается читаемость кода и не возникает конфликта имен констант.&lt;br /&gt;
&lt;br /&gt;
== Поля ==&lt;br /&gt;
&lt;br /&gt;
Поле класса — это некоторый объект, используемый объектом данного класса.&lt;br /&gt;
&lt;br /&gt;
Объявление поля начинается с одного из трех ключевых слов:&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''var'''&amp;lt;/tt&amp;gt;  — объявление &amp;quot;обычного&amp;quot; поля;&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''const'''&amp;lt;/tt&amp;gt; — данное поле является константой и не может быть изменено;&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''mutable'''&amp;lt;/tt&amp;gt; — значение данного поля не влияет на состояние объекта, и его можно менять даже в методах, объявленных константными.&lt;br /&gt;
&lt;br /&gt;
За ключевым словом следует тип поля и [[идентификатор]] его имени. Тип поля может быть опущен. После имени может стоять символ &amp;quot;=&amp;quot; и выражение, инициализирующее значение данного поля. В целом, синтаксис тот же, что и при объявлении обычной переменой или константы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var int m_x;&lt;br /&gt;
const m_y = 0;&lt;br /&gt;
var m_stream = new stream;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тип поля определяется по следующим правилам:&lt;br /&gt;
* если тип указан явно, ничего определять не надо;&lt;br /&gt;
* если тип не указан, но при объявлении использован инициализатор — типом становится тип результата инициализатора;&lt;br /&gt;
* в противном случае, для поля устанавливается [[Переменные#Нетипированные (динамические) переменные|динамический тип]].&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' В K++ доступ к полям имеет только объект класса — т.е. фактически, все поля находятся в закрытой (private) области видимости. Для предоставления внешним классам доступа к полям следует использовать ''свойства'' (см. ниже).&lt;br /&gt;
&lt;br /&gt;
== Свойства ==&lt;br /&gt;
&lt;br /&gt;
''Свойства'' — это специальные конструкции языка К++, которые позволяют совмещать обращение к данным с вызовом определенного метода. Смысл свойств заключается в том, чтобы программист мог контролировать процесс изменения состояния объекта и своевременно реагировать на это изменение. Свойства бывают доступны на чтение, на запись, или на чтение и на запись одновременно. Это связано с тем, что некоторые свойства объекта (в естественном понимании этого слова), могут предполагать только получение информации о них, другие же могут подразумевать изменение состояния, без возможности чтения. &lt;br /&gt;
&lt;br /&gt;
В существующих языках программирования, таких как C++ тот же функционал реализуется с помощью вызова специальных методов: ''аксессоров'' и ''мутаторов'', которые используются для получения сведений о некотором свойстве или для записи соответственно. Однако, это делает код менее читаемым, особенно в случае мутаторов. Свойства же, позволяют работать с собой подобно обычным полям или объектам, используя операторы. &lt;br /&gt;
&lt;br /&gt;
Приведем два примера, которые позволят понять смысл свойств и их отличие от обычных полей класса.&lt;br /&gt;
&lt;br /&gt;
Предположим, что у нас есть класс, отвечающий за чтение состояния некоторого устройства. Допустим, состояние представляется целым числом и должно определяться по мере обращения. Если бы мы писали на языке C++, то мы оформили бы это в виде метода:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
class MyDevice {&lt;br /&gt;
    int GetState();&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Везде, где нам потребовалось бы читать состояние устройства мы должны были писать что-то типа:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int current_state = Device.GetState();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В случае с К++, чтение свойств осуществляется подобно обычным полям. Перепишем вышеописанный пример на язык К++: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
class MyDevice {&lt;br /&gt;
    function int GetState();&lt;br /&gt;
    property int state read GetState;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Соответственно, обращение к свойству состояния будет выглядеть так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var current_state = Device.state;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При обращении к свойству &amp;lt;tt&amp;gt;state&amp;lt;/tt&amp;gt;  будет автоматически вызыван метод &amp;lt;tt&amp;gt;GetState()&amp;lt;/tt&amp;gt;, результат которого будет возвращен как значение свойства. Вышеописанный пример кому-то может показаться странным, ведь получается, что мы усложнили код класса ради сомнительного выигрыша в коде обращения. На самом деле, в реальных условиях, с настоящими классами, с большим количеством свойств и в сложных выражениях, выигрыш становится куда более заметен. Сравните два примера одного и того же участка кода, один из которых написан на C++, другой на K++. Несмотря на то, что приведенный код тоже взят &amp;quot;с потолка&amp;quot;, разница в читаемости уже более заметна. В целом, чем сложнее выражение и чем больше в нем применяется операций присваивания и доступа к полям классов — тем большее преимущество дает использование свойств:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
Object1.SetStatus(Object2.GetStatus() &amp;gt; 0 ? Object2.GetStatus() : DefaultObject.GetStatus());&lt;br /&gt;
printf(&amp;quot;object %s (%d) located at %s : status changed to %u&amp;quot;, &lt;br /&gt;
    Object1.GetName(), Object1.GetIndex(), Object1.GetLocation(), Object1.GetStatus());&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
Object1.status = Object2.status &amp;gt; 0 ? Object2.status : DefaultObject.status;&lt;br /&gt;
println(&amp;quot;object % (%) located at % : status changed to %&amp;quot;, &lt;br /&gt;
    Object1.name, Object1.index, Object1.location, Object1.status);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В качестве второго примера мы приведем код, более близкий к реальной жизни. Как известно, многие элементы управления современных графических интерфейсов могут находится в состоянии &amp;quot;активен&amp;quot; или &amp;quot;не активен&amp;quot;. Неактивные элементы не реагируют на действия пользователя (например, кнопки не будут нажиматься) и как правило окрашиваются в оттенки серого (для того чтобы нельзя было их спутать с активными элементами). Естественно, это поведение определяется некоторым полем в объекте элемента управления. В зависимости от его значения, библиотека графического интерфейса будет по разному обрабатывать и отрисовывать этот элемент управления.&lt;br /&gt;
&lt;br /&gt;
В языке К++ это поведение можно легко описать, используя двусторонние свойства, то есть такие, которые можно использовать как на чтение так и на запись. Логично предположить, что чтение такого свойства не должно сказываться на самом элементе управления, в то время как запись в свойство должна дать команду элементу управления изменить свое состояние и соответственно внешний вид. Вот пример описания некоторого абстрактного класса элемента управления:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
class Widget {&lt;br /&gt;
    var m_Enabled = true; //поле, хранящее текущее состояние активности&lt;br /&gt;
    function void SetEnabled(const value) {&lt;br /&gt;
        var old_value = m_Enabled;&lt;br /&gt;
        m_Enabled = value;&lt;br /&gt;
        if (old_value != m_Enabled)&lt;br /&gt;
            Invalidate(); //Состояние изменилось, обновляем элемент управления&lt;br /&gt;
    }&lt;br /&gt;
    property enabled read m_Enabled write SetEnabled;&lt;br /&gt;
    //далее идет остальная часть класса, например методы отрисовки&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь, если мы унаследуем некоторый класс от данного класса и переопределим соответствующие методы отрисовки, то у класса потомка так же можно будет использовать свойство &amp;lt;tt&amp;gt;enabled&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var myForm = new Form; //создаем окно&lt;br /&gt;
var myButton = Button.CreateAtPos(myForm, 10, 10); //добавляем кнопку&lt;br /&gt;
myButton.caption = &amp;quot;Click me!&amp;quot;; //устанавливаем подпись&lt;br /&gt;
myButton.OnClick += { |x| x.enabled = false; }; //подключаем обработчик события&lt;br /&gt;
myForm.Show(); //показываем окно&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Приведенный выше код создаст окно и разместит на нем кнопку (подразумевается, что класс &amp;lt;tt&amp;gt;Button&amp;lt;/tt&amp;gt; унаследован от нашего класса &amp;lt;tt&amp;gt;Widget&amp;lt;/tt&amp;gt;). Затем устанавливаются свойства кнопки, такие как подпись и [[Блоки|блок]] обработчика события &amp;lt;tt&amp;gt;OnClick&amp;lt;/tt&amp;gt;. При нажатии на кнопку она станет неактивной.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
В заключение, кратко опишем синтаксис объявления свойства и поясним его. Итак, объявление любого свойства начинается с указания ключевого слова &amp;lt;tt&amp;gt;'''property'''&amp;lt;/tt&amp;gt;, после которого идет [[идентификатор]] типа свойства. Тип может быть опущен, тогда для свойства будет определен [[Переменные#Нетипированные (динамические) переменные|динамический тип]]. Затем указывается идентификатор имени свойства. &lt;br /&gt;
&lt;br /&gt;
Оставшаяся часть зависит от того, какое свойство объявляется:&lt;br /&gt;
&lt;br /&gt;
* Если объявляется свойство на чтение, то указывается ключевое слово &amp;lt;tt&amp;gt;'''read'''&amp;lt;/tt&amp;gt;, после которого идет либо идентификатор имени поля, которое нужно читать, либо имя метода, который должен использоваться как ''аксессор''. В роли аксессора может выступать метод, не принимающий параметров и возвращающий некоторое значение, которое будет возвращаться как значение свойства.&lt;br /&gt;
* Если объявляется свойство на запись, то указывается, соответственно ключевое слово &amp;lt;tt&amp;gt;'''write'''&amp;lt;/tt&amp;gt; после которого идет либо имя поля, которое нужно записывать, либо имя метода, который должен использоваться как ''мутатор''. В качестве мутатора может выступать метод, принимающий один параметр. Возвращаемое значение игнорируется, так что оно может быть любым.&lt;br /&gt;
* Если объявляется свойство, доступное как на чтение так и на запись, то указываются обе части, причем первой идет часть чтения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' Если тип свойства указан явно, то в зависимости от типа поля либо типа возвращаемого значения аксессора, может быть выполнена операция [[Приведение типов|приведения типов]]. Разумеется, если тип поля или результат аксессора неприводим к указанному типу свойства, то будет выдано сообщение об ошибке. Аналогичная ситуация обстоит и с параметром мутатора.&lt;br /&gt;
&lt;br /&gt;
Кратко, синтаксис объявления свойства можно описать в стиле справки к командам оболочки:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
property [тип] &amp;lt;имя&amp;gt; [read &amp;lt;аксессор|поле&amp;gt;] [write &amp;lt;мутатор|поле&amp;gt;];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Расширения ==&lt;br /&gt;
&lt;br /&gt;
Иногда бывает необходимо расширить функциональность некоторого существующего класса без порождения дочернего класса. Это может быть необходимо в тех случаях, когда исходный класс уже используется в коде программы и порождение нового класса нарушило бы спецификацию на интерфейс, либо потребовало значительных изменений в исходных текстах программы. В таких случаях целесообразно применять т. н. ''расширения классов''. Синтаксически, конструкция расширения практически не отличается от конструкции объявления класса, однако методы и свойства перечисленные в нем, дополняются к исходному классу, то есть наследования не происходит.&lt;br /&gt;
&lt;br /&gt;
Как правило, расширения применяются к классам [[Стандартной библиотека Gide|стандартной библиотеки]], либо к [[unmanaged код|неуправляемым классам]].&lt;br /&gt;
&lt;br /&gt;
В качестве примера приведем код, расширяющий функциональность класса &amp;lt;tt&amp;gt;[[Стандартные типы данных#Целые числа|int]]&amp;lt;/tt&amp;gt; с помощью свойства &amp;lt;tt&amp;gt;factorial&amp;lt;/tt&amp;gt;. Расширения объявляются путем указания ключевого слова &amp;lt;tt&amp;gt;'''extend'''&amp;lt;/tt&amp;gt;, после которого указывается [[идентификатор]] имени класса, который следует расширить. Затем идет тело расширения, такое же как при описании классов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
package intmod_fact;&lt;br /&gt;
import std;&lt;br /&gt;
external console_stream STDOUT;&lt;br /&gt;
function void println(const string s) { STDOUT.print(s + &amp;quot;\n&amp;quot;); }&lt;br /&gt;
&lt;br /&gt;
extend int {&lt;br /&gt;
    const function ubigint GetFactorial() {&lt;br /&gt;
        var ubigint result = 1, int x;&lt;br /&gt;
        for (x = this; x &amp;gt; 1; --x)&lt;br /&gt;
            result *= x;&lt;br /&gt;
        return result;&lt;br /&gt;
    }&lt;br /&gt;
    property ubigint factorial read GetFactorial;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
export function main() {&lt;br /&gt;
    println(&amp;quot;Factorial of 10 is &amp;quot; + 10.factorial);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;6-14: Мы объявляем расширение класса &amp;lt;tt&amp;gt;[[Стандартные типы данных#Целые числа|int]]&amp;lt;/tt&amp;gt;, реализованного в [[Стандартная библиотека gide|стандартной библиотеке]]. Добавляется частный метод &amp;lt;tt&amp;gt;GetFactorial()&amp;lt;/tt&amp;gt;, и свойство &amp;lt;tt&amp;gt;factorial&amp;lt;/tt&amp;gt;, связанное с методом. Как видно из названия, метод рассчитывает факториал числа, которое содержится в объекте. В данном контексте, специальная переменная ''this'' имеет тип &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt; и ссылается на сам объект. Таким образом, для числа 10 переменная ''this'' будет равна 10.&lt;br /&gt;
&lt;br /&gt;
;17: Здесь мы видим применение расширения в действии. Константа 10 на момент компиляции преобразуется в [[Константы#Константные объекты|константный объект]] класса &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;, который подобно любому другому объекту этого же класса будет иметь свойство &amp;lt;tt&amp;gt;factorial&amp;lt;/tt&amp;gt;, которое мы и используем. При попытке чтения из этого свойства будет вызван метод &amp;lt;tt&amp;gt;GetFactorial()&amp;lt;/tt&amp;gt;, результат выполнения которого возвращается как значение свойства, то есть как факториал числа. &amp;lt;!--Его мы вызываем с помощью специального синтаксиса, для передачи блока в качестве [[Функции#Аргументы|параметра функции]]. При этом, сам блок указывается прямо в коде вызова функции. Тело блока состоит из одного вызова функции, выводящей текущее число в стандартный поток вывода. --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
: Обратите внимание, что функция &amp;lt;tt&amp;gt;println()&amp;lt;/tt&amp;gt;, принимает в качестве параметра [[Стандартные типы данных#Строки|строку]], в то время как тип свойства определен как &amp;lt;tt&amp;gt;[[Стандартные типы данных#Целые числа|ubigint]]&amp;lt;/tt&amp;gt;. В этом нет ничего странного, потому что класс &amp;lt;tt&amp;gt;ubigint&amp;lt;/tt&amp;gt; имеет [[Типы операторов#Операторы приведения типов|оператор приведения типа]] к классу &amp;lt;tt&amp;gt;[[Стандартные типы данных#Строки|string]]&amp;lt;/tt&amp;gt;, который вызывается компилятором автоматически. Таким образом, при вычислении значения выражения в скобках, сперва значение факториала ''приводится'' к типу строки, которая складываясь со строкой слева от оператора &amp;lt;tt&amp;gt;+&amp;lt;/tt&amp;gt; передается в качестве параметра функции.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' При работе с расширениями существует одно важное ограничение. Расширять классы можно только методами и свойствами, но не полями. Это связано с внутренней организацией языка К++ и виртуальной машины. Дополнительно стоит отметить, что методы объявленные в расширении будут перекрывать соответствующие им методы класса (имеется в виду ситуация когда имена и наборы параметров полностью совпадают). Важно понимать, что такое перекрытие не является объявлением виртуального метода — происходит именно замещение старого метода новым. &lt;br /&gt;
&lt;br /&gt;
== Смотри также ==&lt;/div&gt;</summary>
		<author><name>KroTozeR</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%9A%D0%BB%D0%B0%D1%81%D1%81%D1%8B_%D0%B8_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B</id>
		<title>Классы и объекты</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%9A%D0%BB%D0%B0%D1%81%D1%81%D1%8B_%D0%B8_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B"/>
				<updated>2007-10-05T11:25:09Z</updated>
		
		<summary type="html">&lt;p&gt;KroTozeR: /* Наследование */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== История развития ООП ==&lt;br /&gt;
&lt;br /&gt;
Для того чтобы понять, что же такое классы и объекты, сперва необходимо проследить историю развития программирования. А конкретнее, историю возникновения концепции ООП. Автор верит, что знание истории возникновения тех или иных мыслей и идей может помочь читателю осознать необходимость нововведений, и главное — их преимуществ перед существовавшими в то время решениями.&lt;br /&gt;
&lt;br /&gt;
=== Возникновение языков программирования ===&lt;br /&gt;
&lt;br /&gt;
На заре зарождения вычислительных машин их приходилось программировать поистине &amp;quot;вручную&amp;quot;. Все, что было в руках  программиста это пульт управления ЭВМ. На шестнадцатеричной клавиатуре (а еще раньше на пульте с тумблерами) программист задавал некоторый адрес ячейки памяти, затем он мог либо выполнить операцию чтения — тогда на табло появлялись цифры, соответствующие значению ячейки памяти, либо операцию записи — при этом, по указанному адресу записывалось значение, набранное на клавиатуре данных. Затем, программист переходил к следующей ячейке, и так повторялось до тех пор, пока в память ЭВМ не была внесена вся программа. На программистах (точнее, на операторах ЭВМ) лежала огромная ответственность! Одна ошибка, один неверно установленный переключатель или одна пропущенная команда неминуемо вели к ошибкам в работе программы, а, следовательно, и к ошибкам в расчетах. Могли потребоваться недели, и даже месяцы на поиск этой ошибки и на ее исправление! Естественно, ни о каких языках программирования тогда не могло идти и речи.&lt;br /&gt;
&lt;br /&gt;
=== Появление ассемблера ===&lt;br /&gt;
&lt;br /&gt;
Впоследствии, программисты смекнули, что команды можно записывать в виде мнемонических обозначений или мнемоник — то, что раньше применялось только для удобства записи на бумаге — было стандартизировано и приспособлено как ''язык'' общения человека и ЭВМ. Так появился первый язык программирования — ''язык ассемблера''. Конечно, языком его можно назвать с некоторой натяжкой, ведь он не обеспечивал и десятой доли тех возможностей (вроде автоматического разбора арифметических выражений), которые мы привыкли ассоциировать с языками программирования. Тем не менее, ассемблер выполнял свою главную и основную функцию — избавлял программиста от необходимости работать с памятью (и адресами) напрямую. Вместо этого, программист записывал свои команды в стандартной форме, понятной ЭВМ. Далее выполнялась программа ''транслятор'', которая преобразовывала исходный текст программы в поток машинных команд, которые уже можно исполнять.&lt;br /&gt;
&lt;br /&gt;
=== Концепция языка высокого уровня ===&lt;br /&gt;
&lt;br /&gt;
...С увеличением сложности программ, программировать на ассемблере становилось все сложнее и сложнее.  Ввиду естественных ограничений человеческой памяти и внимания, написание программ и их отладка стали настолько сложными, что люди всерьез подошли к рассмотрению идеи языка высокого уровня — некоторой системы обозначений и абстрактных команд, которая позволила бы записывать программы в абстрактной форме, не заботясь о том, как располагать в памяти код и данные, как их структурировать и т. д. Всю эту работу брал на себя компилятор. Кроме того, он обеспечивал программиста удобным способом записи математических выражений — в естественной форме. При этом, компилятор сам &amp;quot;разворачивал&amp;quot; эти выражения в наборы инструкций ассемблера, попутно подставляя значения констант и адреса переменных. Это дало возможность программистам записывать формулы вычислений в натуральном виде, что уменьшало трудозатраты, ускоряло написание программ и уменьшало вероятность ошибок. Тем не менее, многие авторитеты того времени очень негативно отзывались о языках высокого уровня. В то время языки были довольно несовершенными и генерировали &amp;quot;ужасный&amp;quot; с точки зрения программистов код. Код был не оптимален, занимал огромное по тем временам количество памяти и работал медленнее, чем та же программа, написанная на ассемблере. Смешно сказать, но в то время многие не верили в то, что будущее за ЯП высокого уровня; их считали не более чем игрушкой для &amp;quot;чайников&amp;quot;, возжелавших вообразить себя настоящими программистами. &lt;br /&gt;
&lt;br /&gt;
Но время шло, количество приверженцев нового подхода постоянно увеличивалось. Сами же компиляторы становились все более мощными и генерировали все более компактный и оптимальный код. Дошло до того, что компилятор с оптимизатором в некоторых случаях генерировал код, более качественный, чем это делал программист. С этого момента ЯП высокого уровня заняли свое место в истории и в инструментарии любого разработчика.&lt;br /&gt;
&lt;br /&gt;
=== Структурное программирование ===&lt;br /&gt;
&lt;br /&gt;
С развитием языков программирования появились новые концепции и новые парадигмы программирования. От линейного моноблочного программирования, при котором программа писалась единым &amp;quot;куском&amp;quot; от начала до конца, перешли к программам модульным и структурным. При них программа представляла уже совокупность процедур (функций), которые вызывали друг друга в ходе работы программы. Процедуры представляли собой подпрограммы, решающие отдельные частные задачи. При этом код получался более читаемым, и облегчалась его отладка. &lt;br /&gt;
&lt;br /&gt;
Опять же, в ходе усложнения решаемых задач и, вследствие этого, увеличения количества переменных с которыми приходилось работать программисту, возникла идея группировки некоторых переменных в группы или структуры. Структуры формировались по назначению и содержали в себе переменные, имеющие отношение к одной и той же сущности. Это значительно повысило читаемость программ и уменьшило количество ошибок в них.&lt;br /&gt;
&lt;br /&gt;
=== Объектно-ориентированное программирование ===&lt;br /&gt;
&lt;br /&gt;
Ну и наконец, одна светлая голова додумалась до мысли: &amp;quot;а что если в структурах группировать не только переменные, но и сами процедуры которые должны работать с этими переменными?&amp;quot;. В результате получилось то, что мы сейчас называем классом — то есть, некоторая обособленная функциональная сущность, которая сама хранит свои данные, а главное сама умеет их обрабатывать. Теперь программисту не нужно помнить, какая из процедур отвечает за некоторое действие над такими-то переменными — он просто берет объект и работает с ним. Все что происходит с объектом внутри — это его личное дело.&lt;br /&gt;
&lt;br /&gt;
Последним шагом к современному пониманию программ явились концепции [http://ru.wikipedia.org/wiki/Полиморфизм_(программирование) полиморфизма], [http://ru.wikipedia.org/wiki/Инкапсуляция_(программирование) инкапсуляции] и [http://ru.wikipedia.org/wiki/Наследование_(программирование) наследования]. Не будем пока углубляться в суть этих понятий, отметим только, что их введение сформировало современное понимание объектно-ориентированного программирования.&lt;br /&gt;
&lt;br /&gt;
При написании программы на объектно-ориентированном языке, программист строит математическую модель взаимодействия различных сущностей. Каждая из сущностей это свой мир, у которого есть свои законы и особенности. При этом сущности могут быть как конкретные, вроде &amp;quot;сетевой интерфейс&amp;quot; или &amp;quot;файл&amp;quot;, так и совершенно абстрактные, например &amp;quot;отношение&amp;quot; или &amp;quot;ошибка&amp;quot;. Программист описывает каждую из сущностей в отдельности, обособлено от остальных. Вся необходимая для работы информация хранится внутри, а для взаимодействия с внешним миром предусмотрен ''интерфейс'' — некоторая совокупность ''свойств'' данной сущности (отражающих ее внутреннее состояние) и способов взаимодействия с ней — ''методов''.&lt;br /&gt;
&lt;br /&gt;
В ходе работы программы сущности могут взаимодействовать, читая и записывая свойства и вызывая методы друг друга, использовать друг друга как подсистемы, порождать новые сущности и т. д. Получается, что при написании программы, программист переносит свое внутреннее представление того как он видит эту программу, то из чего она состоит и как отдельные ее части взаимодействуют. Теперь не приходится адаптировать свое понимание проблемы к конкретным инструментальным средствам и возможностям языка программирования (конечно, это все же происходит, но уже гораздо менее заметно).&lt;br /&gt;
&lt;br /&gt;
В терминах современных языков программирования такие сущности называются ''классами'', в смысле ''классами сущностей''. А отдельные представители этих классов называются ''экземплярами'', ''инстанциями'' (на английский манер) или ''объектами''. Более подробно, различие между классами и объектами будет рассмотрено ниже.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Итак, любой современный объектно-ориентированный язык оперирует понятиями классов и объектов. Точно такой же подход нашел свое применение в нашей виртуальной машине. Основой всей платформы Gide является объектно-ориентированный принцип. Причем, в этом смысле она является более объектно-ориентированной, нежели традиционные ЯП вроде C++. В C++ существуют понятия элементарных типов. Это сделано в целях производительности и было продиктовано архитектурой самого языка. В классических языках программирования, элементарные типы, так или иначе, отражают сущности из &amp;quot;реального мира&amp;quot;. Например, целочисленные типы int и short соответствуют 32х и 16ти разрядным регистрам процессора, указатели и строки соответствуют представлению данных в памяти и т. д. В Gide это не так. Все с чем оперирует виртуальная машина — это объекты. Соответственно, не существует понятия элементарных типов (просто нет критерия, который бы позволил отделить одно от другого). &lt;br /&gt;
&lt;br /&gt;
Язык K++ в полной мере наследует идеологию Gide. Скажем, для него нет отличия между типом &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt; (целое число) и некоторым пользовательским классом &amp;lt;tt&amp;gt;MyWeirdClass&amp;lt;/tt&amp;gt;: везде, где можно использовать &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;, можно использовать &amp;lt;tt&amp;gt;MyWeirdClass&amp;lt;/tt&amp;gt; и наоборот. Более того, это позволяет работать с системными классами так же, как с пользовательскими! Например, ничто не мешает унаследовать свой класс от класса &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;, равно как ничто не мешает определить математические операторы для класса &amp;lt;tt&amp;gt;MyWeirdClass&amp;lt;/tt&amp;gt; и использовать объекты этого класса в арифметических выражениях. При этом изменится логика работы всего языка. К примеру, после добавления некоторого метода к классу int можно будет вызывать методы у всех его экземпляров, даже тех, что представлены числовыми константами внутри самого языка!&lt;br /&gt;
&lt;br /&gt;
== Понятие класса ==&lt;br /&gt;
&lt;br /&gt;
Что такое ''класс'' проще всего объяснить на примерах. Представьте, что вас спрашивают &amp;quot;что такое яблоко?&amp;quot;. Скорее всего, вы ответите что-то вроде: &amp;quot;яблоки, это вкусные плоды, растущие на деревьях — яблонях; они бывают разных цветов и размеров&amp;quot;. Заметьте, что когда мы описываем ''яблоки как понятие'', мы не имеем в виду некоторый конкретный объект, а скорее описываем наше обобщенное представление о них. Если же вас попросят описать совершенно конкретное яблоко, лежащее на блюдечке перед вами, вы будете говорить о нем по другому: &amp;quot;это яблоко, оно красное, сочное, судя по всему спелое. С черенком, на котором остался листик, и маленькой червоточинкой&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Разница заключается в том, что когда вы говорили ''о яблоках'', вы описывали свое представление яблок, как ''класса'' объектов. Когда вы описывали ''яблоко'', то вы имели в виду конкретный ''экземпляр'', или ''объект''. Говоря о классе, вы можете описать только те свойства, что принадлежат всем яблокам; когда же вы описываете объект, то в первую очередь имеете в виду его индивидуальные особенности (свойства). Тем не менее, описание объекта начинается с упоминания его класса (&amp;quot;это яблоко,...&amp;quot;), а затем уже свойств объекта (ведь &amp;quot;сочным и спелым&amp;quot; может быть и апельсин). Это важная особенность объектно-ориентированного подхода. &lt;br /&gt;
&lt;br /&gt;
Другой пример: если вас попросить &amp;quot;представьте дерево&amp;quot;, то вы либо представите некоторое совершенно абстрактное, усредненное дерево, либо попросите уточнить, какое именно дерево имеется в виду. Ваше сознание из имеющейся информации смогло уяснить только самые общие сведения о классе. Но этой информации не достаточно, для более детального описания. Это тоже важно, поскольку в этом простом примере кроется сущность механизма наследования — постепенного уточнения классами-потомками общих черт своих предков. Таким образом, и яблоня, и груша — деревья. Но яблони отличаются от груш. Получается, что классы ''яблони'' и ''груши'' имеют общего предка — класс ''дерево''.&lt;br /&gt;
&lt;br /&gt;
Таким образом, понятия классов и объектов это не математическая абстракция, а скорее часть нашего восприятия мира, того как мы мыслим.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из примеров выше мы смогли уяснить следующее:&lt;br /&gt;
&lt;br /&gt;
* Классы, это некоторые абстрактные сущности, задающие общие черты своих объектов&lt;br /&gt;
* Все объекты одного класса похожи друг на друга, но имеют некоторые индивидуальные особенности&lt;br /&gt;
* Классы могут наследоваться, расширяя набор свойств класса родителя своими собственными&lt;br /&gt;
&lt;br /&gt;
Перейдем теперь ближе к основной теме нашего повествования, а именно языку К++:&lt;br /&gt;
&lt;br /&gt;
С точки зрения языка, ''класс'' представляет собой набор следующих элементов:&lt;br /&gt;
* ''полей'', т.е. переменных, хранящих индивидуальные особенности объектов, &lt;br /&gt;
* ''методов'', т.е. функций, определяющих поведение данного объекта;&lt;br /&gt;
* ''свойств'', определяющих взаимодействие других объектов с объектами данного класса.&lt;br /&gt;
&lt;br /&gt;
''Поля'' — это переменные, которые относятся к некоторому конкретному экземпляру нашего класса. Каждый экземпляр имеет свою копию набора переменных, таким образом, они могут хранить свое состояние (например, показатель &amp;quot;спелости&amp;quot;, в примере с яблоками). Эти переменные доступны только самому классу, доступ извне для них запрещен. Для того чтобы частично разрешить этот доступ, применяются ''свойства''. Сами свойства будут описаны позже, здесь стоит отметить только то, что свойство может быть доступно &amp;quot;только на чтение&amp;quot;, &amp;quot;только на запись&amp;quot; или &amp;quot;и на чтение и на запись&amp;quot;. Свойство может быть связано либо с некоторым полем, либо с методом. Например, если свойство доступно &amp;quot;только на чтение&amp;quot; то его можно использовать для получения значения, но не для его записи (то есть, такое свойство не может фигурировать в качестве [[lvalue]]).&lt;br /&gt;
&lt;br /&gt;
''Методы'' — это тот самый, связанный с данными код (вспомните [[Классы и объекты#История развития ООП|историю ООП]]) который, естественно, может работать с переменными объекта (то есть с полями) и служит для описания поведения данного класса объектов.&lt;br /&gt;
&lt;br /&gt;
Класс может иметь одного или нескольких родителей (опять же, подробнее об этом см. ниже)&lt;br /&gt;
&lt;br /&gt;
Методы и свойства класса могут находиться в различных областях видимости. Это обеспечивается с помощью [[Спецификаторы доступа|спецификаторов доступа]]:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''private'''&amp;lt;/tt&amp;gt; — Частная собственность! Видимость только внутри методов данного класса&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''protected'''&amp;lt;/tt&amp;gt; — &amp;quot;Семейная реликвия&amp;quot;, доступ внутри методов данного класса и всех его дочерних классов&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''public'''&amp;lt;/tt&amp;gt; — видимость и доступ для всех&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' По умолчанию методы имеют видимость &amp;lt;tt&amp;gt;'''private'''&amp;lt;/tt&amp;gt;, в то время как свойства — &amp;lt;tt&amp;gt;'''public'''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Приведем, наконец, пример объявления класса:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
class MyWeirdClass {&lt;br /&gt;
    var m_x = 0;  // поле m_x, изначально проинициализированное нулем&lt;br /&gt;
    const m_y = 1; // поле-константа m_y&lt;br /&gt;
&lt;br /&gt;
    // методы класса&lt;br /&gt;
    public const function int get_mul() { return m_x * m_y; }&lt;br /&gt;
    public function void set_mul(int x) { m_x = x / m_y; }&lt;br /&gt;
&lt;br /&gt;
    // свойство класса&lt;br /&gt;
    public property mul read get_mul write set_mul;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;1: Как у любого нормального разумного существа, у класса есть &amp;quot;голова&amp;quot; и &amp;quot;тело&amp;quot;. Ключевое слово &amp;lt;tt&amp;gt;'''class'''&amp;lt;/tt&amp;gt; начинает объявление класса. Далее за ним следует [[идентификатор]] имени класса, после чего идет тело класса.&lt;br /&gt;
&lt;br /&gt;
;3-4: Здесь мы видим объявление двух полей класса — переменной ''m_x'' и константы ''m_y'', которые, подобно обычным переменным инициализируются тут же, на месте объявления (камень в огород C++). Зачем нужны поля-константы, описано в главе [[Константы]].  &lt;br /&gt;
&lt;br /&gt;
;7-8: Для доступа к состоянию объекта, определены два метода: ''аксессор'' &amp;lt;tt&amp;gt;get_mul()&amp;lt;/tt&amp;gt; и ''мутатор'' &amp;lt;tt&amp;gt;set_mul()&amp;lt;/tt&amp;gt;. Подобные конструкции применяются настолько часто, что им были даны специальные имена. Как видно из названия, первый метод дает доступ к значению, второй изменяет или мутирует его.&lt;br /&gt;
&lt;br /&gt;
;11: Завершается объявление класса объявлением свойства ''mul'', которое связывается с аксессором и мутатором. Думаю, читатель уже догадался, что это свойство типа &amp;quot;чтение и запись&amp;quot;. Таким образом, при обращении к свойству на чтение, будет вызван аксессор, а результат его выполнения будет возвращен в качестве значения свойства. И, наоборот, при попытке записать в свойство некоторое значение, будет вызван мутатор, в качестве аргумента которому будет передано это самое значение, а уж сам мутатор позаботится о том, чтобы оно было &amp;quot;доставлено по адресу&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
: '''Примечание:''' Зачем нужны такие сложности, и зачем дублировать вроде бы одинаковый функционал, будет описано ниже.&lt;br /&gt;
&lt;br /&gt;
== Понятие объекта ==&lt;br /&gt;
&lt;br /&gt;
Собственно, понятие объекта уже много раз было затронуто выше по повествованию. Поэтому здесь приведем лишь небольшое определение: Под ''объектом'' подразумевается экземпляр того или иного класса, т.е. некоторая сущность, поведение которой задается соответствующим классом.&lt;br /&gt;
&lt;br /&gt;
Для создания объекта того или иного класса служит оператор &amp;lt;tt&amp;gt;'''new'''&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
    var myWeirdObject = new MyWeirdClass;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь мы видим типичную конструкцию объявления переменной, однако в инициализаторе переменной находится всего один оператор, за которым следует [[идентификатор]] имени класса, экземпляр которого мы хотим создать.&lt;br /&gt;
&lt;br /&gt;
== Наследование ==&lt;br /&gt;
&lt;br /&gt;
Под ''наследованием'' классов понимается механизм такого создания (объявления) класса, при котором он расширяет функционал одного или нескольких уже существующих классов (родителей). Вспомните пример с деревьями. Когда мы говорим, что класс ''яблоня'' наследуется от класса ''дерево'' — это значит что ''яблоня'' унаследует все свойства своего класса-родителя, некоторые из которых он может изменить, ну и дополнить своими собственными свойствами. Опыт нам подсказывает, что у любого дерева есть листья (для простоты не будем вспоминать про хвойные), однако не любое дерево плодоносит яблоками. Если же рассмотреть сами яблоки, то можно сказать, что класс ''яблоко'' унаследован от класса ''фрукт'', который определяет что фрукты (и соответственно яблоки) должны расти на деревьях.&lt;br /&gt;
&lt;br /&gt;
Таким образом, наследование гарантирует, что к дочерним классам применимы все операции, доступные в родительском классе: любой алгоритм, работающий с объектами родительского класса, может работать с объектами его дочерних классов. &lt;br /&gt;
&lt;br /&gt;
Для задания наследования, в объявлении класса следует указать ключевое слово &amp;lt;tt&amp;gt;'''extends'''&amp;lt;/tt&amp;gt;,  за которым необходимо перечислить список идентификаторов классов-родителей, разделяя их запятыми:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
// коробка&lt;br /&gt;
class Box { &lt;br /&gt;
    // из чего сделана коробка?&lt;br /&gt;
    public const function string material() { return &amp;quot;Картон&amp;quot;; }&lt;br /&gt;
&lt;br /&gt;
    // что в коробке?&lt;br /&gt;
    public const function string contents() { return &amp;quot;Пусто&amp;quot;; }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// коробка с картошкой&lt;br /&gt;
class BoxWithPotatoes extends Box { &lt;br /&gt;
    public const function string contents() { return &amp;quot;Картошка&amp;quot;; }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function OutputBox(const Box b) {&lt;br /&gt;
    STDOUT.print(&amp;quot;Материал: &amp;quot; + b.material() + &amp;quot;, содержит: &amp;quot; + b.contents() + &amp;quot;\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function main() {&lt;br /&gt;
    var b1 = new Box;&lt;br /&gt;
    var b2 = new BoxWithPotatoes;&lt;br /&gt;
    OutputBox(b1); // Материал: Картон, содержит: Пусто&lt;br /&gt;
    OutputBox(b2); // Материал: Картон, содержит: Картошка&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;2-7: В этом примере мы создаем класс &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt;, который представляет собой некоторую коробку. Мы определяем ее свойства, такие как ''материал'' и ''содержимое''.&lt;br /&gt;
&lt;br /&gt;
;10-12: Далее мы определяем класс &amp;lt;tt&amp;gt;BoxWithPotatoes&amp;lt;/tt&amp;gt; (''коробка с картошкой''), который наследуется от класса &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt;, и тем самым заимствует свойства материала и содержимого, но первое он переопределяет (в случае методов это называется ''перекрытием'') собственным методом.&lt;br /&gt;
&lt;br /&gt;
;14-16: Мы определяем некоторую [[Функции|функцию]] для работы с нашими классами, которая будет отображать их состояние. Заметьте, что в качестве [[Функции#Аргументы|аргумента функции]] передается экземпляр класса &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt;, то есть класса-родителя. При этом мы предполагаем, что любой класс, унаследованный от базового класса, будет обладать необходимым нам интерфейсом, а именно методами получения информации о свойствах (аксессорами мы их не называем, потому что они не связаны с конкретным полем; это было бы неверно).&lt;br /&gt;
&lt;br /&gt;
;18-23: Объявляется функция &amp;lt;tt&amp;gt;main()&amp;lt;/tt&amp;gt;, внутри которой и происходит самое интересное. Сначала мы создаем два экземпляра ''b1'' и ''b2'' классов &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt; и &amp;lt;tt&amp;gt;BoxWithPotatoes&amp;lt;/tt&amp;gt; соответственно. А затем, вызываем вышеописанную функцию &amp;lt;tt&amp;gt;OutputBox()&amp;lt;/tt&amp;gt;, которая отображает содержимое. Вывод в терминал (написан в комментарии к вызову) показывает, как это все работает.&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' при использовании множественного наследования существует одно серьезное ограничение: его нельзя применять для наследования от классов стандартной библиотеки. Это ограничение связано с архитектурой платформы Gide. Однако его можно обойти с помощью создания [[Класс-обертка|классов-оберток]] для системного класса, с последующим наследованием от него нового класса.&lt;br /&gt;
&lt;br /&gt;
== Методы ==&lt;br /&gt;
&lt;br /&gt;
''Метод'' — это некоторый код, связанный с объектом и управляющий его поведением. Управление может заключаться в изменении переменных постояния объекта (полей), либо выполнением некоторых операций над ними.&lt;br /&gt;
&lt;br /&gt;
При объявлении метода могут быть указаны следующие ключевые слова, в указанном порядке:&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''private'''&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;'''protected'''&amp;lt;/tt&amp;gt; или &amp;lt;tt&amp;gt;'''public'''&amp;lt;/tt&amp;gt; — определяют область видимости метода&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''static'''&amp;lt;/tt&amp;gt; — указывает, что метод является ''статическим'' (см. ниже)&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''const'''&amp;lt;/tt&amp;gt; — метод не изменяет объект&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''function'''&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;'''operator'''&amp;lt;/tt&amp;gt; или &amp;lt;tt&amp;gt;'''constructor'''&amp;lt;/tt&amp;gt; указывает, что объявляется: ''метод'', ''[[Операторы|оператор]]'' или ''конструктор'' (см. ниже)&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''const'''&amp;lt;/tt&amp;gt; — метод возвращает результат, который нельзя изменять&lt;br /&gt;
&lt;br /&gt;
После этого указывается тип, возвращаемый методом. Если он опущен — возвращается [[Переменные#Нетипированные (динамические) переменные|динамическая переменная]]; если вместо типа указано ключевое слово &amp;lt;tt&amp;gt;'''void'''&amp;lt;/tt&amp;gt; — метод не возвращает результата. Следом за типом идет имя метода, затем — перечисление [[Функции#Аргументы|аргументов]] в скобках. Подробнее об объявлении функций и передаче параметров, можно прочитать в главе [[Функции]].&lt;br /&gt;
&lt;br /&gt;
Тело метода может быть объявлено как непосредственно в теле класса, так и вынесено за его пределы, например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
class MyClass {&lt;br /&gt;
    public const function string F1() { return &amp;quot;smth&amp;quot;; }&lt;br /&gt;
    public const function string F2();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function string MyClass::F2() {&lt;br /&gt;
    return F1();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;6: При вынесении функции за пределы класса, имя соответствующего метода предворяется именем класса из которого он был вынесен; имена отделяются друг от друга символом &amp;quot;двойное двоеточие&amp;quot; ( &amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt; ); дополнительно — в заголовке вынесенной функции необходимо указать тип возвращаемого значения и параметры функции, все остальные ключевые слова указывать не обязательно.&lt;br /&gt;
&lt;br /&gt;
;7: В теле метода доступны все поля, методы и свойства данного класса и его предков. Например, в коде приведенном выше, метод &amp;lt;tt&amp;gt;F2()&amp;lt;/tt&amp;gt; вызывает метод &amp;lt;tt&amp;gt;F1()&amp;lt;/tt&amp;gt; для того же объекта.&lt;br /&gt;
&lt;br /&gt;
=== Статические методы ===&lt;br /&gt;
&lt;br /&gt;
''Статический метод класса'' — это метод, относящиеся к данному классу, но не объекту этого класса. Т.е. это некоторая вспомогательная для данного класса функция.&lt;br /&gt;
&lt;br /&gt;
При объявлении статического метода нужно указать ключевое слово &amp;lt;tt&amp;gt;'''static'''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В теле статического метода нет возможности напрямую обращаться к другим методам данного класса, т.к. статическому методу недоступен объект класса. Фактически, единственным отличием статического метода от обычной функции является то, что такой метод может обращаться к защищенным полям и методам класса некоторого другого объекта. Подобный подход широко применяется при написании ''конструкторов'' (см. ниже).&lt;br /&gt;
&lt;br /&gt;
Пример:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
class MyClass {&lt;br /&gt;
    public static function string Info() { return &amp;quot;Я MyClass!&amp;quot;; }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function f() {&lt;br /&gt;
    // Вызов статического метода:&lt;br /&gt;
    var myClassInfo = MyClass.Info();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Конструкторы ===&lt;br /&gt;
&lt;br /&gt;
В ходе написания программы часто приходится создавать новые объекты. При этом, объекту требуется установить некоторое начальное состояние. Разумеется, это выполняется либо путем написания инициализаторов соответствующих полей, либо занчения полям присваиваются явным образом. Но что делать, если объект может иметь несколько начальных состояний? То есть, в зависимости от некоторых условий, одним и тем же полям объекта могут быть присвоены различные наборы значений. Тут уже одними инициализаторами не обойтись. Присваивать значения можно прямо в коде программы, однако это не очень красивое решение, поскольку один и тот же объект может создаваться в нескольких местах программы и придется копировать один и тот же участок кода, инициализирующий поля объекта. Недостаток этого подхода в том, что при большом количестве полей, программист может забыть проинициализировать некоторе поле, либо при изменении условий инициализации он может изменить их только в одном месте программы, забыв что объект может создаваться и в других местах. Более разумным является подход, при котором программист пишет функцию, инициализирующую поля объекта. При этом, весь код собирается в одном месте и вероятность ошибок значительно понижается. &lt;br /&gt;
&lt;br /&gt;
Конструкторы развивают эту идею, дополняя код инициализации полей кодом создания самого экземпляра объекта. То есть, в конструкторе собирается весь код относящийся к созданию инстанции класса. Итак, ''конструктор класса'' — это специальный метод, инициализирующий объект класса. С точки зрения языка, конструктор — это статический метод класса, возвращающий экземпляр данного класса.&lt;br /&gt;
&lt;br /&gt;
Таким образом, следующие объявления в рамках класса эквивалентны:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
public constructor Create();&lt;br /&gt;
public static MyClass Create();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тело конструктора чаще всего выглядит следующим образом: сначала создается экземпляр класса при помощи оператора &amp;lt;tt&amp;gt;'''new'''&amp;lt;/tt&amp;gt;, затем производятся некоторые действия, инициализующие этот объект, и, наконец, этот объект возвращается в качестве результата. &lt;br /&gt;
&lt;br /&gt;
В качестве примера приведем пример реализации некоторого абстрактного класса &amp;lt;tt&amp;gt;MyStream&amp;lt;/tt&amp;gt;, использующего системную реализацию класса &amp;lt;tt&amp;gt;stream&amp;lt;/tt&amp;gt;, и определяющую собственный конструктор:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
class MyStream {&lt;br /&gt;
    var string m_URL;&lt;br /&gt;
    var stream m_Stream;&lt;br /&gt;
public:&lt;br /&gt;
    static const MODE_READ = 1;&lt;br /&gt;
    static const MODE_WRITE = 2;&lt;br /&gt;
    constructor open(const string url, int mode) {&lt;br /&gt;
        var self = new MyStream;&lt;br /&gt;
        self.m_Stream.open(url, mode);&lt;br /&gt;
        self.m_URL = url;&lt;br /&gt;
        return self;&lt;br /&gt;
    }&lt;br /&gt;
    // прочие методы (опущены для краткости)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;2-3: Объявляются поля ''m_URL'' и ''m_Stream'' нашего класса, которые будут инициализироваться в конструкторе. &lt;br /&gt;
&lt;br /&gt;
;5-6: В публичной области класса объявляются статические константы ''MODE_READ'' и ''MODE_WRITE'', которые задают желаемый режим доступа к открываемому потоку. Это единственный случай, когда поле класса доступно на прямой доступ извне.&lt;br /&gt;
&lt;br /&gt;
;7: Объявляется конструктор &amp;lt;tt&amp;gt;open()&amp;lt;/tt&amp;gt;, принимающий в качестве параметров [[URL]] ресурса который требуется открыть и число, задающее с помощью вышеописанных констант режим доступа к потоку. В теле конструктора мы создаем инстанцию ''self'' нашего класса. Затем производится попытка открытия потока ''m_Stream'': если операция пройдет успешно, то происходит инициализация оставшегося поля ''m_URL'' и выход из конструктора с возвратом созданной инстанции; если же операция открытия потока провалится, то будет сгенерировано ''[[Обработка исключений|исключение]]'' и выполнение конструктора прекратится (управление будет передано &amp;quot;наверх&amp;quot;, вызывающему коду).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Использовать наш класс можно примерно так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;var data = MyStream.open(&amp;quot;http://www.deeptown.org/index.html&amp;quot;, MyStream.MODE_READ);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на второй параметр функции, где мы передаем константу ''MODE_READ'', объявленную внутри самого класса. Подобный подход, когда константы используемые при работе с классом инкапсулируются в тело класса, помогает сконцентрировать код в одном месте и избежать многих ошибок. В результате повышается читаемость кода и не возникает конфликта имен констант.&lt;br /&gt;
&lt;br /&gt;
== Поля ==&lt;br /&gt;
&lt;br /&gt;
Поле класса — это некоторый объект, используемый объектом данного класса.&lt;br /&gt;
&lt;br /&gt;
Объявление поля начинается с одного из трех ключевых слов:&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''var'''&amp;lt;/tt&amp;gt;  — объявление &amp;quot;обычного&amp;quot; поля;&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''const'''&amp;lt;/tt&amp;gt; — данное поле является константой и не может быть изменено;&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''mutable'''&amp;lt;/tt&amp;gt; — значение данного поля не влияет на состояние объекта, и его можно менять даже в методах, объявленных константными.&lt;br /&gt;
&lt;br /&gt;
За ключевым словом следует тип поля и [[идентификатор]] его имени. Тип поля может быть опущен. После имени может стоять символ &amp;quot;=&amp;quot; и выражение, инициализирующее значение данного поля. В целом, синтаксис тот же, что и при объявлении обычной переменой или константы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var int m_x;&lt;br /&gt;
const m_y = 0;&lt;br /&gt;
var m_stream = new stream;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тип поля определяется по следующим правилам:&lt;br /&gt;
* если тип указан явно, ничего определять не надо;&lt;br /&gt;
* если тип не указан, но при объявлении использован инициализатор — типом становится тип результата инициализатора;&lt;br /&gt;
* в противном случае, для поля устанавливается [[Переменные#Нетипированные (динамические) переменные|динамический тип]].&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' В K++ доступ к полям имеет только объект класса — т.е. фактически, все поля находятся в закрытой (private) области видимости. Для предоставления внешним классам доступа к полям следует использовать ''свойства'' (см. ниже).&lt;br /&gt;
&lt;br /&gt;
== Свойства ==&lt;br /&gt;
&lt;br /&gt;
''Свойства'' — это специальные конструкции языка К++, которые позволяют совмещать обращение к данным с вызовом определенного метода. Смысл свойств заключается в том, чтобы программист мог контролировать процесс изменения состояния объекта и своевременно реагировать на это изменение. Свойства бывают доступны на чтение, на запись, или на чтение и на запись одновременно. Это связано с тем, что некоторые свойства объекта (в естественном понимании этого слова), могут предполагать только получение информации о них, другие же могут подразумевать изменение состояния, без возможности чтения. &lt;br /&gt;
&lt;br /&gt;
В существующих языках программирования, таких как C++ тот же функционал реализуется с помощью вызова специальных методов: ''аксессоров'' и ''мутаторов'', которые используются для получения сведений о некотором свойстве или для записи соответственно. Однако, это делает код менее читаемым, особенно в случае мутаторов. Свойства же, позволяют работать с собой подобно обычным полям или объектам, используя операторы. &lt;br /&gt;
&lt;br /&gt;
Приведем два примера, которые позволят понять смысл свойств и их отличие от обычных полей класса.&lt;br /&gt;
&lt;br /&gt;
Предположим, что у нас есть класс, отвечающий за чтение состояния некоторого устройства. Допустим, состояние представляется целым числом и должно определяться по мере обращения. Если бы мы писали на языке C++, то мы оформили бы это в виде метода:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
class MyDevice {&lt;br /&gt;
    int GetState();&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Везде, где нам потребовалось бы читать состояние устройства мы должны были писать что-то типа:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int current_state = Device.GetState();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В случае с К++, чтение свойств осуществляется подобно обычным полям. Перепишем вышеописанный пример на язык К++: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
class MyDevice {&lt;br /&gt;
    function int GetState();&lt;br /&gt;
    property int state read GetState;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Соответственно, обращение к свойству состояния будет выглядеть так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var current_state = Device.state;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При обращении к свойству &amp;lt;tt&amp;gt;state&amp;lt;/tt&amp;gt;  будет автоматически вызыван метод &amp;lt;tt&amp;gt;GetState()&amp;lt;/tt&amp;gt;, результат которого будет возвращен как значение свойства. Вышеописанный пример кому-то может показаться странным, ведь получается, что мы усложнили код класса ради сомнительного выигрыша в коде обращения. На самом деле, в реальных условиях, с настоящими классами, с большим количеством свойств и в сложных выражениях, выигрыш становится куда более заметен. Сравните два примера одного и того же участка кода, один из которых написан на C++, другой на K++. Несмотря на то, что приведенный код тоже взят &amp;quot;с потолка&amp;quot;, разница в читаемости уже более заметна. В целом, чем сложнее выражение и чем больше в нем применяется операций присваивания и доступа к полям классов — тем большее преимущество дает использование свойств:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
Object1.SetStatus(Object2.GetStatus() &amp;gt; 0 ? Object2.GetStatus() : DefaultObject.GetStatus());&lt;br /&gt;
printf(&amp;quot;object %s (%d) located at %s : status changed to %u&amp;quot;, &lt;br /&gt;
    Object1.GetName(), Object1.GetIndex(), Object1.GetLocation(), Object1.GetStatus());&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
Object1.status = Object2.status &amp;gt; 0 ? Object2.status : DefaultObject.status;&lt;br /&gt;
println(&amp;quot;object % (%) located at % : status changed to %&amp;quot;, &lt;br /&gt;
    Object1.name, Object1.index, Object1.location, Object1.status);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В качестве второго примера мы приведем код, более близкий к реальной жизни. Как известно, многие элементы управления современных графических интерфейсов могут находится в состоянии &amp;quot;активен&amp;quot; или &amp;quot;не активен&amp;quot;. Неактивные элементы не реагируют на действия пользователя (например, кнопки не будут нажиматься) и как правило окрашиваются в оттенки серого (для того чтобы нельзя было их спутать с активными элементами). Естественно, это поведение определяется некоторым полем в объекте элемента управления. В зависимости от его значения, библиотека графического интерфейса будет по разному обрабатывать и отрисовывать этот элемент управления.&lt;br /&gt;
&lt;br /&gt;
В языке К++ это поведение можно легко описать, используя двусторонние свойства, то есть такие, которые можно использовать как на чтение так и на запись. Логично предположить, что чтение такого свойства не должно сказываться на самом элементе управления, в то время как запись в свойство должна дать команду элементу управления изменить свое состояние и соответственно внешний вид. Вот пример описания некоторого абстрактного класса элемента управления:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
class Widget {&lt;br /&gt;
    var m_Enabled = true; //поле, хранящее текущее состояние активности&lt;br /&gt;
    function void SetEnabled(const value) {&lt;br /&gt;
        var old_value = m_Enabled;&lt;br /&gt;
        m_Enabled = value;&lt;br /&gt;
        if (old_value != m_Enabled)&lt;br /&gt;
            Invalidate(); //Состояние изменилось, обновляем элемент управления&lt;br /&gt;
    }&lt;br /&gt;
    property enabled read m_Enabled write SetEnabled;&lt;br /&gt;
    //далее идет остальная часть класса, например методы отрисовки&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь, если мы унаследуем некоторый класс от данного класса и переопределим соответствующие методы отрисовки, то у класса потомка так же можно будет использовать свойство &amp;lt;tt&amp;gt;enabled&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var myForm = new Form; //создаем окно&lt;br /&gt;
var myButton = Button.CreateAtPos(myForm, 10, 10); //добавляем кнопку&lt;br /&gt;
myButton.caption = &amp;quot;Click me!&amp;quot;; //устанавливаем подпись&lt;br /&gt;
myButton.OnClick += { |x| x.enabled = false; }; //подключаем обработчик события&lt;br /&gt;
myForm.Show(); //показываем окно&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Приведенный выше код создаст окно и разместит на нем кнопку (подразумевается, что класс &amp;lt;tt&amp;gt;Button&amp;lt;/tt&amp;gt; унаследован от нашего класса &amp;lt;tt&amp;gt;Widget&amp;lt;/tt&amp;gt;). Затем устанавливаются свойства кнопки, такие как подпись и [[Блоки|блок]] обработчика события &amp;lt;tt&amp;gt;OnClick&amp;lt;/tt&amp;gt;. При нажатии на кнопку она станет неактивной.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
В заключение, кратко опишем синтаксис объявления свойства и поясним его. Итак, объявление любого свойства начинается с указания ключевого слова &amp;lt;tt&amp;gt;'''property'''&amp;lt;/tt&amp;gt;, после которого идет [[идентификатор]] типа свойства. Тип может быть опущен, тогда для свойства будет определен [[Переменные#Нетипированные (динамические) переменные|динамический тип]]. Затем указывается идентификатор имени свойства. &lt;br /&gt;
&lt;br /&gt;
Оставшаяся часть зависит от того, какое свойство объявляется:&lt;br /&gt;
&lt;br /&gt;
* Если объявляется свойство на чтение, то указывается ключевое слово &amp;lt;tt&amp;gt;'''read'''&amp;lt;/tt&amp;gt;, после которого идет либо идентификатор имени поля, которое нужно читать, либо имя метода, который должен использоваться как ''аксессор''. В роли аксессора может выступать метод, не принимающий параметров и возвращающий некоторое значение, которое будет возвращаться как значение свойства.&lt;br /&gt;
* Если объявляется свойство на запись, то указывается, соответственно ключевое слово &amp;lt;tt&amp;gt;'''write'''&amp;lt;/tt&amp;gt; после которого идет либо имя поля, которое нужно записывать, либо имя метода, который должен использоваться как ''мутатор''. В качестве мутатора может выступать метод, принимающий один параметр. Возвращаемое значение игнорируется, так что оно может быть любым.&lt;br /&gt;
* Если объявляется свойство, доступное как на чтение так и на запись, то указываются обе части, причем первой идет часть чтения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' Если тип свойства указан явно, то в зависимости от типа поля либо типа возвращаемого значения аксессора, может быть выполнена операция [[Приведение типов|приведения типов]]. Разумеется, если тип поля или результат аксессора неприводим к указанному типу свойства, то будет выдано сообщение об ошибке. Аналогичная ситуация обстоит и с параметром мутатора.&lt;br /&gt;
&lt;br /&gt;
Кратко, синтаксис объявления свойства можно описать в стиле справки к командам оболочки:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
property [тип] &amp;lt;имя&amp;gt; [read &amp;lt;аксессор|поле&amp;gt;] [write &amp;lt;мутатор|поле&amp;gt;];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Расширения ==&lt;br /&gt;
&lt;br /&gt;
Иногда бывает необходимо расширить функциональность некоторого существующего класса без порождения дочернего класса. Это может быть необходимо в тех случаях, когда исходный класс уже используется в коде программы и порождение нового класса нарушило бы спецификацию на интерфейс, либо потребовало значительных изменений в исходных текстах программы. В таких случаях целесообразно применять т. н. ''расширения классов''. Синтаксически, конструкция расширения практически не отличается от конструкции объявления класса, однако методы и свойства перечисленные в нем, дополняются к исходному классу, то есть наследования не происходит.&lt;br /&gt;
&lt;br /&gt;
Как правило, расширения применяются к классам [[Стандартной библиотека Gide|стандартной библиотеки]], либо к [[unmanaged код|неуправляемым классам]].&lt;br /&gt;
&lt;br /&gt;
В качестве примера приведем код, расширяющий функциональность класса &amp;lt;tt&amp;gt;[[Стандартные типы данных#Целые числа|int]]&amp;lt;/tt&amp;gt; с помощью свойства &amp;lt;tt&amp;gt;factorial&amp;lt;/tt&amp;gt;. Расширения объявляются путем указания ключевого слова &amp;lt;tt&amp;gt;'''extend'''&amp;lt;/tt&amp;gt;, после которого указывается [[идентификатор]] имени класса, который следует расширить. Затем идет тело расширения, такое же как при описании классов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
package intmod_fact;&lt;br /&gt;
import std;&lt;br /&gt;
external console_stream STDOUT;&lt;br /&gt;
function void println(const string s) { STDOUT.print(s + &amp;quot;\n&amp;quot;); }&lt;br /&gt;
&lt;br /&gt;
extend int {&lt;br /&gt;
    const function ubigint GetFactorial() {&lt;br /&gt;
        var ubigint result = 1, int x;&lt;br /&gt;
        for (x = this; x &amp;gt; 1; --x)&lt;br /&gt;
            result *= x;&lt;br /&gt;
        return result;&lt;br /&gt;
    }&lt;br /&gt;
    property ubigint factorial read GetFactorial;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
export function main() {&lt;br /&gt;
    println(&amp;quot;Factorial of 10 is &amp;quot; + 10.factorial);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;6-14: Мы объявляем расширение класса &amp;lt;tt&amp;gt;[[Стандартные типы данных#Целые числа|int]]&amp;lt;/tt&amp;gt;, реализованного в [[Стандартная библиотека gide|стандартной библиотеке]]. Добавляется частный метод &amp;lt;tt&amp;gt;GetFactorial()&amp;lt;/tt&amp;gt;, и свойство &amp;lt;tt&amp;gt;factorial&amp;lt;/tt&amp;gt;, связанное с методом. Как видно из названия, метод рассчитывает факториал числа, которое содержится в объекте. В данном контексте, специальная переменная ''this'' имеет тип &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt; и ссылается на сам объект. Таким образом, для числа 10 переменная ''this'' будет равна 10.&lt;br /&gt;
&lt;br /&gt;
;17: Здесь мы видим применение расширения в действии. Константа 10 на момент компиляции преобразуется в [[Константы#Константные объекты|константный объект]] класса &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;, который подобно любому другому объекту этого же класса будет иметь свойство &amp;lt;tt&amp;gt;factorial&amp;lt;/tt&amp;gt;, которое мы и используем. При попытке чтения из этого свойства будет вызван метод &amp;lt;tt&amp;gt;GetFactorial()&amp;lt;/tt&amp;gt;, результат выполнения которого возвращается как значение свойства, то есть как факториал числа. &amp;lt;!--Его мы вызываем с помощью специального синтаксиса, для передачи блока в качестве [[Функции#Аргументы|параметра функции]]. При этом, сам блок указывается прямо в коде вызова функции. Тело блока состоит из одного вызова функции, выводящей текущее число в стандартный поток вывода. --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
: Обратите внимание, что функция &amp;lt;tt&amp;gt;println()&amp;lt;/tt&amp;gt;, принимает в качестве параметра [[Стандартные типы данных#Строки|строку]], в то время как тип свойства определен как &amp;lt;tt&amp;gt;[[Стандартные типы данных#Целые числа|ubigint]]&amp;lt;/tt&amp;gt;. В этом нет ничего странного, потому что класс &amp;lt;tt&amp;gt;ubigint&amp;lt;/tt&amp;gt; имеет [[Типы операторов#Операторы приведения типов|оператор приведения типа]] к классу &amp;lt;tt&amp;gt;[[Стандартные типы данных#Строки|string]]&amp;lt;/tt&amp;gt;, который вызывается компилятором автоматически. Таким образом, при вычислении значения выражения в скобках, сперва значение факториала ''приводится'' к типу строки, которая складываясь со строкой слева от оператора &amp;lt;tt&amp;gt;+&amp;lt;/tt&amp;gt; передается в качестве параметра функции.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' При работе с расширениями существует одно важное ограничение. Расширять классы можно только методами и свойствами, но не полями. Это связано с внутренней организацией языка К++ и виртуальной машины. Дополнительно стоит отметить, что методы объявленные в расширении будут перекрывать соответствующие им методы класса (имеется в виду ситуация когда имена и наборы параметров полностью совпадают). Важно понимать, что такое перекрытие не является объявлением виртуального метода — происходит именно замещение старого метода новым. &lt;br /&gt;
&lt;br /&gt;
== Смотри также ==&lt;/div&gt;</summary>
		<author><name>KroTozeR</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%9A%D0%BB%D0%B0%D1%81%D1%81%D1%8B_%D0%B8_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B</id>
		<title>Классы и объекты</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%9A%D0%BB%D0%B0%D1%81%D1%81%D1%8B_%D0%B8_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B"/>
				<updated>2007-10-05T11:22:26Z</updated>
		
		<summary type="html">&lt;p&gt;KroTozeR: /* Понятие класса */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== История развития ООП ==&lt;br /&gt;
&lt;br /&gt;
Для того чтобы понять, что же такое классы и объекты, сперва необходимо проследить историю развития программирования. А конкретнее, историю возникновения концепции ООП. Автор верит, что знание истории возникновения тех или иных мыслей и идей может помочь читателю осознать необходимость нововведений, и главное — их преимуществ перед существовавшими в то время решениями.&lt;br /&gt;
&lt;br /&gt;
=== Возникновение языков программирования ===&lt;br /&gt;
&lt;br /&gt;
На заре зарождения вычислительных машин их приходилось программировать поистине &amp;quot;вручную&amp;quot;. Все, что было в руках  программиста это пульт управления ЭВМ. На шестнадцатеричной клавиатуре (а еще раньше на пульте с тумблерами) программист задавал некоторый адрес ячейки памяти, затем он мог либо выполнить операцию чтения — тогда на табло появлялись цифры, соответствующие значению ячейки памяти, либо операцию записи — при этом, по указанному адресу записывалось значение, набранное на клавиатуре данных. Затем, программист переходил к следующей ячейке, и так повторялось до тех пор, пока в память ЭВМ не была внесена вся программа. На программистах (точнее, на операторах ЭВМ) лежала огромная ответственность! Одна ошибка, один неверно установленный переключатель или одна пропущенная команда неминуемо вели к ошибкам в работе программы, а, следовательно, и к ошибкам в расчетах. Могли потребоваться недели, и даже месяцы на поиск этой ошибки и на ее исправление! Естественно, ни о каких языках программирования тогда не могло идти и речи.&lt;br /&gt;
&lt;br /&gt;
=== Появление ассемблера ===&lt;br /&gt;
&lt;br /&gt;
Впоследствии, программисты смекнули, что команды можно записывать в виде мнемонических обозначений или мнемоник — то, что раньше применялось только для удобства записи на бумаге — было стандартизировано и приспособлено как ''язык'' общения человека и ЭВМ. Так появился первый язык программирования — ''язык ассемблера''. Конечно, языком его можно назвать с некоторой натяжкой, ведь он не обеспечивал и десятой доли тех возможностей (вроде автоматического разбора арифметических выражений), которые мы привыкли ассоциировать с языками программирования. Тем не менее, ассемблер выполнял свою главную и основную функцию — избавлял программиста от необходимости работать с памятью (и адресами) напрямую. Вместо этого, программист записывал свои команды в стандартной форме, понятной ЭВМ. Далее выполнялась программа ''транслятор'', которая преобразовывала исходный текст программы в поток машинных команд, которые уже можно исполнять.&lt;br /&gt;
&lt;br /&gt;
=== Концепция языка высокого уровня ===&lt;br /&gt;
&lt;br /&gt;
...С увеличением сложности программ, программировать на ассемблере становилось все сложнее и сложнее.  Ввиду естественных ограничений человеческой памяти и внимания, написание программ и их отладка стали настолько сложными, что люди всерьез подошли к рассмотрению идеи языка высокого уровня — некоторой системы обозначений и абстрактных команд, которая позволила бы записывать программы в абстрактной форме, не заботясь о том, как располагать в памяти код и данные, как их структурировать и т. д. Всю эту работу брал на себя компилятор. Кроме того, он обеспечивал программиста удобным способом записи математических выражений — в естественной форме. При этом, компилятор сам &amp;quot;разворачивал&amp;quot; эти выражения в наборы инструкций ассемблера, попутно подставляя значения констант и адреса переменных. Это дало возможность программистам записывать формулы вычислений в натуральном виде, что уменьшало трудозатраты, ускоряло написание программ и уменьшало вероятность ошибок. Тем не менее, многие авторитеты того времени очень негативно отзывались о языках высокого уровня. В то время языки были довольно несовершенными и генерировали &amp;quot;ужасный&amp;quot; с точки зрения программистов код. Код был не оптимален, занимал огромное по тем временам количество памяти и работал медленнее, чем та же программа, написанная на ассемблере. Смешно сказать, но в то время многие не верили в то, что будущее за ЯП высокого уровня; их считали не более чем игрушкой для &amp;quot;чайников&amp;quot;, возжелавших вообразить себя настоящими программистами. &lt;br /&gt;
&lt;br /&gt;
Но время шло, количество приверженцев нового подхода постоянно увеличивалось. Сами же компиляторы становились все более мощными и генерировали все более компактный и оптимальный код. Дошло до того, что компилятор с оптимизатором в некоторых случаях генерировал код, более качественный, чем это делал программист. С этого момента ЯП высокого уровня заняли свое место в истории и в инструментарии любого разработчика.&lt;br /&gt;
&lt;br /&gt;
=== Структурное программирование ===&lt;br /&gt;
&lt;br /&gt;
С развитием языков программирования появились новые концепции и новые парадигмы программирования. От линейного моноблочного программирования, при котором программа писалась единым &amp;quot;куском&amp;quot; от начала до конца, перешли к программам модульным и структурным. При них программа представляла уже совокупность процедур (функций), которые вызывали друг друга в ходе работы программы. Процедуры представляли собой подпрограммы, решающие отдельные частные задачи. При этом код получался более читаемым, и облегчалась его отладка. &lt;br /&gt;
&lt;br /&gt;
Опять же, в ходе усложнения решаемых задач и, вследствие этого, увеличения количества переменных с которыми приходилось работать программисту, возникла идея группировки некоторых переменных в группы или структуры. Структуры формировались по назначению и содержали в себе переменные, имеющие отношение к одной и той же сущности. Это значительно повысило читаемость программ и уменьшило количество ошибок в них.&lt;br /&gt;
&lt;br /&gt;
=== Объектно-ориентированное программирование ===&lt;br /&gt;
&lt;br /&gt;
Ну и наконец, одна светлая голова додумалась до мысли: &amp;quot;а что если в структурах группировать не только переменные, но и сами процедуры которые должны работать с этими переменными?&amp;quot;. В результате получилось то, что мы сейчас называем классом — то есть, некоторая обособленная функциональная сущность, которая сама хранит свои данные, а главное сама умеет их обрабатывать. Теперь программисту не нужно помнить, какая из процедур отвечает за некоторое действие над такими-то переменными — он просто берет объект и работает с ним. Все что происходит с объектом внутри — это его личное дело.&lt;br /&gt;
&lt;br /&gt;
Последним шагом к современному пониманию программ явились концепции [http://ru.wikipedia.org/wiki/Полиморфизм_(программирование) полиморфизма], [http://ru.wikipedia.org/wiki/Инкапсуляция_(программирование) инкапсуляции] и [http://ru.wikipedia.org/wiki/Наследование_(программирование) наследования]. Не будем пока углубляться в суть этих понятий, отметим только, что их введение сформировало современное понимание объектно-ориентированного программирования.&lt;br /&gt;
&lt;br /&gt;
При написании программы на объектно-ориентированном языке, программист строит математическую модель взаимодействия различных сущностей. Каждая из сущностей это свой мир, у которого есть свои законы и особенности. При этом сущности могут быть как конкретные, вроде &amp;quot;сетевой интерфейс&amp;quot; или &amp;quot;файл&amp;quot;, так и совершенно абстрактные, например &amp;quot;отношение&amp;quot; или &amp;quot;ошибка&amp;quot;. Программист описывает каждую из сущностей в отдельности, обособлено от остальных. Вся необходимая для работы информация хранится внутри, а для взаимодействия с внешним миром предусмотрен ''интерфейс'' — некоторая совокупность ''свойств'' данной сущности (отражающих ее внутреннее состояние) и способов взаимодействия с ней — ''методов''.&lt;br /&gt;
&lt;br /&gt;
В ходе работы программы сущности могут взаимодействовать, читая и записывая свойства и вызывая методы друг друга, использовать друг друга как подсистемы, порождать новые сущности и т. д. Получается, что при написании программы, программист переносит свое внутреннее представление того как он видит эту программу, то из чего она состоит и как отдельные ее части взаимодействуют. Теперь не приходится адаптировать свое понимание проблемы к конкретным инструментальным средствам и возможностям языка программирования (конечно, это все же происходит, но уже гораздо менее заметно).&lt;br /&gt;
&lt;br /&gt;
В терминах современных языков программирования такие сущности называются ''классами'', в смысле ''классами сущностей''. А отдельные представители этих классов называются ''экземплярами'', ''инстанциями'' (на английский манер) или ''объектами''. Более подробно, различие между классами и объектами будет рассмотрено ниже.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Итак, любой современный объектно-ориентированный язык оперирует понятиями классов и объектов. Точно такой же подход нашел свое применение в нашей виртуальной машине. Основой всей платформы Gide является объектно-ориентированный принцип. Причем, в этом смысле она является более объектно-ориентированной, нежели традиционные ЯП вроде C++. В C++ существуют понятия элементарных типов. Это сделано в целях производительности и было продиктовано архитектурой самого языка. В классических языках программирования, элементарные типы, так или иначе, отражают сущности из &amp;quot;реального мира&amp;quot;. Например, целочисленные типы int и short соответствуют 32х и 16ти разрядным регистрам процессора, указатели и строки соответствуют представлению данных в памяти и т. д. В Gide это не так. Все с чем оперирует виртуальная машина — это объекты. Соответственно, не существует понятия элементарных типов (просто нет критерия, который бы позволил отделить одно от другого). &lt;br /&gt;
&lt;br /&gt;
Язык K++ в полной мере наследует идеологию Gide. Скажем, для него нет отличия между типом &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt; (целое число) и некоторым пользовательским классом &amp;lt;tt&amp;gt;MyWeirdClass&amp;lt;/tt&amp;gt;: везде, где можно использовать &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;, можно использовать &amp;lt;tt&amp;gt;MyWeirdClass&amp;lt;/tt&amp;gt; и наоборот. Более того, это позволяет работать с системными классами так же, как с пользовательскими! Например, ничто не мешает унаследовать свой класс от класса &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;, равно как ничто не мешает определить математические операторы для класса &amp;lt;tt&amp;gt;MyWeirdClass&amp;lt;/tt&amp;gt; и использовать объекты этого класса в арифметических выражениях. При этом изменится логика работы всего языка. К примеру, после добавления некоторого метода к классу int можно будет вызывать методы у всех его экземпляров, даже тех, что представлены числовыми константами внутри самого языка!&lt;br /&gt;
&lt;br /&gt;
== Понятие класса ==&lt;br /&gt;
&lt;br /&gt;
Что такое ''класс'' проще всего объяснить на примерах. Представьте, что вас спрашивают &amp;quot;что такое яблоко?&amp;quot;. Скорее всего, вы ответите что-то вроде: &amp;quot;яблоки, это вкусные плоды, растущие на деревьях — яблонях; они бывают разных цветов и размеров&amp;quot;. Заметьте, что когда мы описываем ''яблоки как понятие'', мы не имеем в виду некоторый конкретный объект, а скорее описываем наше обобщенное представление о них. Если же вас попросят описать совершенно конкретное яблоко, лежащее на блюдечке перед вами, вы будете говорить о нем по другому: &amp;quot;это яблоко, оно красное, сочное, судя по всему спелое. С черенком, на котором остался листик, и маленькой червоточинкой&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Разница заключается в том, что когда вы говорили ''о яблоках'', вы описывали свое представление яблок, как ''класса'' объектов. Когда вы описывали ''яблоко'', то вы имели в виду конкретный ''экземпляр'', или ''объект''. Говоря о классе, вы можете описать только те свойства, что принадлежат всем яблокам; когда же вы описываете объект, то в первую очередь имеете в виду его индивидуальные особенности (свойства). Тем не менее, описание объекта начинается с упоминания его класса (&amp;quot;это яблоко,...&amp;quot;), а затем уже свойств объекта (ведь &amp;quot;сочным и спелым&amp;quot; может быть и апельсин). Это важная особенность объектно-ориентированного подхода. &lt;br /&gt;
&lt;br /&gt;
Другой пример: если вас попросить &amp;quot;представьте дерево&amp;quot;, то вы либо представите некоторое совершенно абстрактное, усредненное дерево, либо попросите уточнить, какое именно дерево имеется в виду. Ваше сознание из имеющейся информации смогло уяснить только самые общие сведения о классе. Но этой информации не достаточно, для более детального описания. Это тоже важно, поскольку в этом простом примере кроется сущность механизма наследования — постепенного уточнения классами-потомками общих черт своих предков. Таким образом, и яблоня, и груша — деревья. Но яблони отличаются от груш. Получается, что классы ''яблони'' и ''груши'' имеют общего предка — класс ''дерево''.&lt;br /&gt;
&lt;br /&gt;
Таким образом, понятия классов и объектов это не математическая абстракция, а скорее часть нашего восприятия мира, того как мы мыслим.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из примеров выше мы смогли уяснить следующее:&lt;br /&gt;
&lt;br /&gt;
* Классы, это некоторые абстрактные сущности, задающие общие черты своих объектов&lt;br /&gt;
* Все объекты одного класса похожи друг на друга, но имеют некоторые индивидуальные особенности&lt;br /&gt;
* Классы могут наследоваться, расширяя набор свойств класса родителя своими собственными&lt;br /&gt;
&lt;br /&gt;
Перейдем теперь ближе к основной теме нашего повествования, а именно языку К++:&lt;br /&gt;
&lt;br /&gt;
С точки зрения языка, ''класс'' представляет собой набор следующих элементов:&lt;br /&gt;
* ''полей'', т.е. переменных, хранящих индивидуальные особенности объектов, &lt;br /&gt;
* ''методов'', т.е. функций, определяющих поведение данного объекта;&lt;br /&gt;
* ''свойств'', определяющих взаимодействие других объектов с объектами данного класса.&lt;br /&gt;
&lt;br /&gt;
''Поля'' — это переменные, которые относятся к некоторому конкретному экземпляру нашего класса. Каждый экземпляр имеет свою копию набора переменных, таким образом, они могут хранить свое состояние (например, показатель &amp;quot;спелости&amp;quot;, в примере с яблоками). Эти переменные доступны только самому классу, доступ извне для них запрещен. Для того чтобы частично разрешить этот доступ, применяются ''свойства''. Сами свойства будут описаны позже, здесь стоит отметить только то, что свойство может быть доступно &amp;quot;только на чтение&amp;quot;, &amp;quot;только на запись&amp;quot; или &amp;quot;и на чтение и на запись&amp;quot;. Свойство может быть связано либо с некоторым полем, либо с методом. Например, если свойство доступно &amp;quot;только на чтение&amp;quot; то его можно использовать для получения значения, но не для его записи (то есть, такое свойство не может фигурировать в качестве [[lvalue]]).&lt;br /&gt;
&lt;br /&gt;
''Методы'' — это тот самый, связанный с данными код (вспомните [[Классы и объекты#История развития ООП|историю ООП]]) который, естественно, может работать с переменными объекта (то есть с полями) и служит для описания поведения данного класса объектов.&lt;br /&gt;
&lt;br /&gt;
Класс может иметь одного или нескольких родителей (опять же, подробнее об этом см. ниже)&lt;br /&gt;
&lt;br /&gt;
Методы и свойства класса могут находиться в различных областях видимости. Это обеспечивается с помощью [[Спецификаторы доступа|спецификаторов доступа]]:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''private'''&amp;lt;/tt&amp;gt; — Частная собственность! Видимость только внутри методов данного класса&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''protected'''&amp;lt;/tt&amp;gt; — &amp;quot;Семейная реликвия&amp;quot;, доступ внутри методов данного класса и всех его дочерних классов&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''public'''&amp;lt;/tt&amp;gt; — видимость и доступ для всех&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' По умолчанию методы имеют видимость &amp;lt;tt&amp;gt;'''private'''&amp;lt;/tt&amp;gt;, в то время как свойства — &amp;lt;tt&amp;gt;'''public'''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Приведем, наконец, пример объявления класса:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
class MyWeirdClass {&lt;br /&gt;
    var m_x = 0;  // поле m_x, изначально проинициализированное нулем&lt;br /&gt;
    const m_y = 1; // поле-константа m_y&lt;br /&gt;
&lt;br /&gt;
    // методы класса&lt;br /&gt;
    public const function int get_mul() { return m_x * m_y; }&lt;br /&gt;
    public function void set_mul(int x) { m_x = x / m_y; }&lt;br /&gt;
&lt;br /&gt;
    // свойство класса&lt;br /&gt;
    public property mul read get_mul write set_mul;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;1: Как у любого нормального разумного существа, у класса есть &amp;quot;голова&amp;quot; и &amp;quot;тело&amp;quot;. Ключевое слово &amp;lt;tt&amp;gt;'''class'''&amp;lt;/tt&amp;gt; начинает объявление класса. Далее за ним следует [[идентификатор]] имени класса, после чего идет тело класса.&lt;br /&gt;
&lt;br /&gt;
;3-4: Здесь мы видим объявление двух полей класса — переменной ''m_x'' и константы ''m_y'', которые, подобно обычным переменным инициализируются тут же, на месте объявления (камень в огород C++). Зачем нужны поля-константы, описано в главе [[Константы]].  &lt;br /&gt;
&lt;br /&gt;
;7-8: Для доступа к состоянию объекта, определены два метода: ''аксессор'' &amp;lt;tt&amp;gt;get_mul()&amp;lt;/tt&amp;gt; и ''мутатор'' &amp;lt;tt&amp;gt;set_mul()&amp;lt;/tt&amp;gt;. Подобные конструкции применяются настолько часто, что им были даны специальные имена. Как видно из названия, первый метод дает доступ к значению, второй изменяет или мутирует его.&lt;br /&gt;
&lt;br /&gt;
;11: Завершается объявление класса объявлением свойства ''mul'', которое связывается с аксессором и мутатором. Думаю, читатель уже догадался, что это свойство типа &amp;quot;чтение и запись&amp;quot;. Таким образом, при обращении к свойству на чтение, будет вызван аксессор, а результат его выполнения будет возвращен в качестве значения свойства. И, наоборот, при попытке записать в свойство некоторое значение, будет вызван мутатор, в качестве аргумента которому будет передано это самое значение, а уж сам мутатор позаботится о том, чтобы оно было &amp;quot;доставлено по адресу&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
: '''Примечание:''' Зачем нужны такие сложности, и зачем дублировать вроде бы одинаковый функционал, будет описано ниже.&lt;br /&gt;
&lt;br /&gt;
== Понятие объекта ==&lt;br /&gt;
&lt;br /&gt;
Собственно, понятие объекта уже много раз было затронуто выше по повествованию. Поэтому здесь приведем лишь небольшое определение: Под ''объектом'' подразумевается экземпляр того или иного класса, т.е. некоторая сущность, поведение которой задается соответствующим классом.&lt;br /&gt;
&lt;br /&gt;
Для создания объекта того или иного класса служит оператор &amp;lt;tt&amp;gt;'''new'''&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
    var myWeirdObject = new MyWeirdClass;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь мы видим типичную конструкцию объявления переменной, однако в инициализаторе переменной находится всего один оператор, за которым следует [[идентификатор]] имени класса, экземпляр которого мы хотим создать.&lt;br /&gt;
&lt;br /&gt;
== Наследование ==&lt;br /&gt;
&lt;br /&gt;
Под ''наследованием'' классов понимается механизм такого создания (объявления) класса, при котором он расширяет функционал одного или нескольких уже существующих классов (родителей). Вспомните пример с деревьями. Когда мы говорим, что класс ''яблоня'' наследуется от класса ''дерево'' — это значит что ''яблоня'' унаследует все свойства своего класса-родителя, некоторые из которых он может изменить, ну и дополнить своими собственными свойствами. Опыт нам подсказывает, что у любого дерева есть листья (для простоты не будем вспоминать про хвойные), однако не любое дерево плодоносит яблоками. Если же рассмотреть сами яблоки, то можно сказать, что класс ''яблоко'' унаследован от класса ''фрукт'', который определяет что фрукты (и соответственно яблоки) должны расти на деревьях.&lt;br /&gt;
&lt;br /&gt;
Таким образом, наследование гарантирует, что к дочерним классам применимы все операции, доступные в родительском классе: любой алгоритм, работающий с объектами родительского класса, может работать с объектами его дочерних классов. &lt;br /&gt;
&lt;br /&gt;
Для задания наследования, в объявлении класса следует указать ключевое слово &amp;lt;tt&amp;gt;'''extends'''&amp;lt;/tt&amp;gt;,  за которым необходимо перечислить список идентификаторов классов-родителей, разделяя их запятыми:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
// коробка&lt;br /&gt;
class Box { &lt;br /&gt;
    // из чего сделана коробка?&lt;br /&gt;
    public const function string material() { return &amp;quot;Картон&amp;quot;; }&lt;br /&gt;
&lt;br /&gt;
    // что в коробке?&lt;br /&gt;
    public const function string contents() { return &amp;quot;Пусто&amp;quot;; }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// коробка с картошкой&lt;br /&gt;
class BoxWithPotatoes extends Box { &lt;br /&gt;
    public const function string contents() { return &amp;quot;Картошка&amp;quot;; }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function OutputBox(const Box b) {&lt;br /&gt;
    STDOUT.print(&amp;quot;Материал: &amp;quot; + b.material() + &amp;quot;, содержит: &amp;quot; + b.contents() + &amp;quot;\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function main() {&lt;br /&gt;
    var b1 = new Box;&lt;br /&gt;
    var b2 = new BoxWithPotatoes;&lt;br /&gt;
    OutputBox(b1); // Материал: Картон, содержит: Пусто&lt;br /&gt;
    OutputBox(b2); // Материал: Картон, содержит: Картошка&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;2-7: В этом примере мы создаем класс &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt;, который представляет собой некоторую коробку. Мы определяем ее свойства, такие как ''материал'' и ''содержимое''.&lt;br /&gt;
&lt;br /&gt;
;10-12: Далее мы определяем класс &amp;lt;tt&amp;gt;BoxWithPotatoes&amp;lt;/tt&amp;gt; (''коробка с картошкой''), который наследуется от класса &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt;, и тем самым заимствует свойства материала и содержимого, но первое он переопределяет (в случае методов это называется ''перекрытием'') собственным методом.&lt;br /&gt;
&lt;br /&gt;
;14-16: Мы определяем некоторую [[Функции|функцию]] для работы с нашими классами, которая будет отображать их состояние. Заметьте, что в качестве [[Функции#Аргументы|аргумента функции]] передается экземпляр класса &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt;, то есть класса-родителя. При этом, мы предполагаем что любой класс, унаследованный от базового класса, будет обладать необходимым нам интерфейсом, а именно методами получения информации о свойствах (аксессорами мы их не называем, потому что они не связаны с конкретным полем; это было бы неверно).&lt;br /&gt;
&lt;br /&gt;
;18-23: Объявляется функция &amp;lt;tt&amp;gt;main()&amp;lt;/tt&amp;gt;, внутри которой и происходит самое интересное. Сначала мы создаем два экземпляра ''b1'' и ''b2'' классов &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt; и &amp;lt;tt&amp;gt;BoxWithPotatoes&amp;lt;/tt&amp;gt; соответственно. А затем, вызываем вышеописанную функцию &amp;lt;tt&amp;gt;OutputBox()&amp;lt;/tt&amp;gt;, которая отображает содержимое. Вывод в терминал (написан в комментарии к вызову) показывает как это все работает.&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' при использовании множественного наследования существует одно серьезное ограничение: его нельзя применять для наследования от классов стандартной библиотеки. Это ограничение связано с архитектурой платформы Gide. Однако, его можно обойти с помощью создания [[Класс-обертка|классов-оберток]] для системного класса, с последующим наследованием от него нового класса.&lt;br /&gt;
&lt;br /&gt;
== Методы ==&lt;br /&gt;
&lt;br /&gt;
''Метод'' — это некоторый код, связанный с объектом и управляющий его поведением. Управление может заключаться в изменении переменных постояния объекта (полей), либо выполнением некоторых операций над ними.&lt;br /&gt;
&lt;br /&gt;
При объявлении метода могут быть указаны следующие ключевые слова, в указанном порядке:&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''private'''&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;'''protected'''&amp;lt;/tt&amp;gt; или &amp;lt;tt&amp;gt;'''public'''&amp;lt;/tt&amp;gt; — определяют область видимости метода&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''static'''&amp;lt;/tt&amp;gt; — указывает, что метод является ''статическим'' (см. ниже)&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''const'''&amp;lt;/tt&amp;gt; — метод не изменяет объект&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''function'''&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;'''operator'''&amp;lt;/tt&amp;gt; или &amp;lt;tt&amp;gt;'''constructor'''&amp;lt;/tt&amp;gt; указывает, что объявляется: ''метод'', ''[[Операторы|оператор]]'' или ''конструктор'' (см. ниже)&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''const'''&amp;lt;/tt&amp;gt; — метод возвращает результат, который нельзя изменять&lt;br /&gt;
&lt;br /&gt;
После этого указывается тип, возвращаемый методом. Если он опущен — возвращается [[Переменные#Нетипированные (динамические) переменные|динамическая переменная]]; если вместо типа указано ключевое слово &amp;lt;tt&amp;gt;'''void'''&amp;lt;/tt&amp;gt; — метод не возвращает результата. Следом за типом идет имя метода, затем — перечисление [[Функции#Аргументы|аргументов]] в скобках. Подробнее об объявлении функций и передаче параметров, можно прочитать в главе [[Функции]].&lt;br /&gt;
&lt;br /&gt;
Тело метода может быть объявлено как непосредственно в теле класса, так и вынесено за его пределы, например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
class MyClass {&lt;br /&gt;
    public const function string F1() { return &amp;quot;smth&amp;quot;; }&lt;br /&gt;
    public const function string F2();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function string MyClass::F2() {&lt;br /&gt;
    return F1();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;6: При вынесении функции за пределы класса, имя соответствующего метода предворяется именем класса из которого он был вынесен; имена отделяются друг от друга символом &amp;quot;двойное двоеточие&amp;quot; ( &amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt; ); дополнительно — в заголовке вынесенной функции необходимо указать тип возвращаемого значения и параметры функции, все остальные ключевые слова указывать не обязательно.&lt;br /&gt;
&lt;br /&gt;
;7: В теле метода доступны все поля, методы и свойства данного класса и его предков. Например, в коде приведенном выше, метод &amp;lt;tt&amp;gt;F2()&amp;lt;/tt&amp;gt; вызывает метод &amp;lt;tt&amp;gt;F1()&amp;lt;/tt&amp;gt; для того же объекта.&lt;br /&gt;
&lt;br /&gt;
=== Статические методы ===&lt;br /&gt;
&lt;br /&gt;
''Статический метод класса'' — это метод, относящиеся к данному классу, но не объекту этого класса. Т.е. это некоторая вспомогательная для данного класса функция.&lt;br /&gt;
&lt;br /&gt;
При объявлении статического метода нужно указать ключевое слово &amp;lt;tt&amp;gt;'''static'''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В теле статического метода нет возможности напрямую обращаться к другим методам данного класса, т.к. статическому методу недоступен объект класса. Фактически, единственным отличием статического метода от обычной функции является то, что такой метод может обращаться к защищенным полям и методам класса некоторого другого объекта. Подобный подход широко применяется при написании ''конструкторов'' (см. ниже).&lt;br /&gt;
&lt;br /&gt;
Пример:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
class MyClass {&lt;br /&gt;
    public static function string Info() { return &amp;quot;Я MyClass!&amp;quot;; }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function f() {&lt;br /&gt;
    // Вызов статического метода:&lt;br /&gt;
    var myClassInfo = MyClass.Info();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Конструкторы ===&lt;br /&gt;
&lt;br /&gt;
В ходе написания программы часто приходится создавать новые объекты. При этом, объекту требуется установить некоторое начальное состояние. Разумеется, это выполняется либо путем написания инициализаторов соответствующих полей, либо занчения полям присваиваются явным образом. Но что делать, если объект может иметь несколько начальных состояний? То есть, в зависимости от некоторых условий, одним и тем же полям объекта могут быть присвоены различные наборы значений. Тут уже одними инициализаторами не обойтись. Присваивать значения можно прямо в коде программы, однако это не очень красивое решение, поскольку один и тот же объект может создаваться в нескольких местах программы и придется копировать один и тот же участок кода, инициализирующий поля объекта. Недостаток этого подхода в том, что при большом количестве полей, программист может забыть проинициализировать некоторе поле, либо при изменении условий инициализации он может изменить их только в одном месте программы, забыв что объект может создаваться и в других местах. Более разумным является подход, при котором программист пишет функцию, инициализирующую поля объекта. При этом, весь код собирается в одном месте и вероятность ошибок значительно понижается. &lt;br /&gt;
&lt;br /&gt;
Конструкторы развивают эту идею, дополняя код инициализации полей кодом создания самого экземпляра объекта. То есть, в конструкторе собирается весь код относящийся к созданию инстанции класса. Итак, ''конструктор класса'' — это специальный метод, инициализирующий объект класса. С точки зрения языка, конструктор — это статический метод класса, возвращающий экземпляр данного класса.&lt;br /&gt;
&lt;br /&gt;
Таким образом, следующие объявления в рамках класса эквивалентны:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
public constructor Create();&lt;br /&gt;
public static MyClass Create();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тело конструктора чаще всего выглядит следующим образом: сначала создается экземпляр класса при помощи оператора &amp;lt;tt&amp;gt;'''new'''&amp;lt;/tt&amp;gt;, затем производятся некоторые действия, инициализующие этот объект, и, наконец, этот объект возвращается в качестве результата. &lt;br /&gt;
&lt;br /&gt;
В качестве примера приведем пример реализации некоторого абстрактного класса &amp;lt;tt&amp;gt;MyStream&amp;lt;/tt&amp;gt;, использующего системную реализацию класса &amp;lt;tt&amp;gt;stream&amp;lt;/tt&amp;gt;, и определяющую собственный конструктор:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
class MyStream {&lt;br /&gt;
    var string m_URL;&lt;br /&gt;
    var stream m_Stream;&lt;br /&gt;
public:&lt;br /&gt;
    static const MODE_READ = 1;&lt;br /&gt;
    static const MODE_WRITE = 2;&lt;br /&gt;
    constructor open(const string url, int mode) {&lt;br /&gt;
        var self = new MyStream;&lt;br /&gt;
        self.m_Stream.open(url, mode);&lt;br /&gt;
        self.m_URL = url;&lt;br /&gt;
        return self;&lt;br /&gt;
    }&lt;br /&gt;
    // прочие методы (опущены для краткости)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;2-3: Объявляются поля ''m_URL'' и ''m_Stream'' нашего класса, которые будут инициализироваться в конструкторе. &lt;br /&gt;
&lt;br /&gt;
;5-6: В публичной области класса объявляются статические константы ''MODE_READ'' и ''MODE_WRITE'', которые задают желаемый режим доступа к открываемому потоку. Это единственный случай, когда поле класса доступно на прямой доступ извне.&lt;br /&gt;
&lt;br /&gt;
;7: Объявляется конструктор &amp;lt;tt&amp;gt;open()&amp;lt;/tt&amp;gt;, принимающий в качестве параметров [[URL]] ресурса который требуется открыть и число, задающее с помощью вышеописанных констант режим доступа к потоку. В теле конструктора мы создаем инстанцию ''self'' нашего класса. Затем производится попытка открытия потока ''m_Stream'': если операция пройдет успешно, то происходит инициализация оставшегося поля ''m_URL'' и выход из конструктора с возвратом созданной инстанции; если же операция открытия потока провалится, то будет сгенерировано ''[[Обработка исключений|исключение]]'' и выполнение конструктора прекратится (управление будет передано &amp;quot;наверх&amp;quot;, вызывающему коду).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Использовать наш класс можно примерно так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;var data = MyStream.open(&amp;quot;http://www.deeptown.org/index.html&amp;quot;, MyStream.MODE_READ);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на второй параметр функции, где мы передаем константу ''MODE_READ'', объявленную внутри самого класса. Подобный подход, когда константы используемые при работе с классом инкапсулируются в тело класса, помогает сконцентрировать код в одном месте и избежать многих ошибок. В результате повышается читаемость кода и не возникает конфликта имен констант.&lt;br /&gt;
&lt;br /&gt;
== Поля ==&lt;br /&gt;
&lt;br /&gt;
Поле класса — это некоторый объект, используемый объектом данного класса.&lt;br /&gt;
&lt;br /&gt;
Объявление поля начинается с одного из трех ключевых слов:&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''var'''&amp;lt;/tt&amp;gt;  — объявление &amp;quot;обычного&amp;quot; поля;&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''const'''&amp;lt;/tt&amp;gt; — данное поле является константой и не может быть изменено;&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''mutable'''&amp;lt;/tt&amp;gt; — значение данного поля не влияет на состояние объекта, и его можно менять даже в методах, объявленных константными.&lt;br /&gt;
&lt;br /&gt;
За ключевым словом следует тип поля и [[идентификатор]] его имени. Тип поля может быть опущен. После имени может стоять символ &amp;quot;=&amp;quot; и выражение, инициализирующее значение данного поля. В целом, синтаксис тот же, что и при объявлении обычной переменой или константы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var int m_x;&lt;br /&gt;
const m_y = 0;&lt;br /&gt;
var m_stream = new stream;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тип поля определяется по следующим правилам:&lt;br /&gt;
* если тип указан явно, ничего определять не надо;&lt;br /&gt;
* если тип не указан, но при объявлении использован инициализатор — типом становится тип результата инициализатора;&lt;br /&gt;
* в противном случае, для поля устанавливается [[Переменные#Нетипированные (динамические) переменные|динамический тип]].&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' В K++ доступ к полям имеет только объект класса — т.е. фактически, все поля находятся в закрытой (private) области видимости. Для предоставления внешним классам доступа к полям следует использовать ''свойства'' (см. ниже).&lt;br /&gt;
&lt;br /&gt;
== Свойства ==&lt;br /&gt;
&lt;br /&gt;
''Свойства'' — это специальные конструкции языка К++, которые позволяют совмещать обращение к данным с вызовом определенного метода. Смысл свойств заключается в том, чтобы программист мог контролировать процесс изменения состояния объекта и своевременно реагировать на это изменение. Свойства бывают доступны на чтение, на запись, или на чтение и на запись одновременно. Это связано с тем, что некоторые свойства объекта (в естественном понимании этого слова), могут предполагать только получение информации о них, другие же могут подразумевать изменение состояния, без возможности чтения. &lt;br /&gt;
&lt;br /&gt;
В существующих языках программирования, таких как C++ тот же функционал реализуется с помощью вызова специальных методов: ''аксессоров'' и ''мутаторов'', которые используются для получения сведений о некотором свойстве или для записи соответственно. Однако, это делает код менее читаемым, особенно в случае мутаторов. Свойства же, позволяют работать с собой подобно обычным полям или объектам, используя операторы. &lt;br /&gt;
&lt;br /&gt;
Приведем два примера, которые позволят понять смысл свойств и их отличие от обычных полей класса.&lt;br /&gt;
&lt;br /&gt;
Предположим, что у нас есть класс, отвечающий за чтение состояния некоторого устройства. Допустим, состояние представляется целым числом и должно определяться по мере обращения. Если бы мы писали на языке C++, то мы оформили бы это в виде метода:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
class MyDevice {&lt;br /&gt;
    int GetState();&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Везде, где нам потребовалось бы читать состояние устройства мы должны были писать что-то типа:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int current_state = Device.GetState();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В случае с К++, чтение свойств осуществляется подобно обычным полям. Перепишем вышеописанный пример на язык К++: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
class MyDevice {&lt;br /&gt;
    function int GetState();&lt;br /&gt;
    property int state read GetState;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Соответственно, обращение к свойству состояния будет выглядеть так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var current_state = Device.state;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При обращении к свойству &amp;lt;tt&amp;gt;state&amp;lt;/tt&amp;gt;  будет автоматически вызыван метод &amp;lt;tt&amp;gt;GetState()&amp;lt;/tt&amp;gt;, результат которого будет возвращен как значение свойства. Вышеописанный пример кому-то может показаться странным, ведь получается, что мы усложнили код класса ради сомнительного выигрыша в коде обращения. На самом деле, в реальных условиях, с настоящими классами, с большим количеством свойств и в сложных выражениях, выигрыш становится куда более заметен. Сравните два примера одного и того же участка кода, один из которых написан на C++, другой на K++. Несмотря на то, что приведенный код тоже взят &amp;quot;с потолка&amp;quot;, разница в читаемости уже более заметна. В целом, чем сложнее выражение и чем больше в нем применяется операций присваивания и доступа к полям классов — тем большее преимущество дает использование свойств:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
Object1.SetStatus(Object2.GetStatus() &amp;gt; 0 ? Object2.GetStatus() : DefaultObject.GetStatus());&lt;br /&gt;
printf(&amp;quot;object %s (%d) located at %s : status changed to %u&amp;quot;, &lt;br /&gt;
    Object1.GetName(), Object1.GetIndex(), Object1.GetLocation(), Object1.GetStatus());&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
Object1.status = Object2.status &amp;gt; 0 ? Object2.status : DefaultObject.status;&lt;br /&gt;
println(&amp;quot;object % (%) located at % : status changed to %&amp;quot;, &lt;br /&gt;
    Object1.name, Object1.index, Object1.location, Object1.status);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В качестве второго примера мы приведем код, более близкий к реальной жизни. Как известно, многие элементы управления современных графических интерфейсов могут находится в состоянии &amp;quot;активен&amp;quot; или &amp;quot;не активен&amp;quot;. Неактивные элементы не реагируют на действия пользователя (например, кнопки не будут нажиматься) и как правило окрашиваются в оттенки серого (для того чтобы нельзя было их спутать с активными элементами). Естественно, это поведение определяется некоторым полем в объекте элемента управления. В зависимости от его значения, библиотека графического интерфейса будет по разному обрабатывать и отрисовывать этот элемент управления.&lt;br /&gt;
&lt;br /&gt;
В языке К++ это поведение можно легко описать, используя двусторонние свойства, то есть такие, которые можно использовать как на чтение так и на запись. Логично предположить, что чтение такого свойства не должно сказываться на самом элементе управления, в то время как запись в свойство должна дать команду элементу управления изменить свое состояние и соответственно внешний вид. Вот пример описания некоторого абстрактного класса элемента управления:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
class Widget {&lt;br /&gt;
    var m_Enabled = true; //поле, хранящее текущее состояние активности&lt;br /&gt;
    function void SetEnabled(const value) {&lt;br /&gt;
        var old_value = m_Enabled;&lt;br /&gt;
        m_Enabled = value;&lt;br /&gt;
        if (old_value != m_Enabled)&lt;br /&gt;
            Invalidate(); //Состояние изменилось, обновляем элемент управления&lt;br /&gt;
    }&lt;br /&gt;
    property enabled read m_Enabled write SetEnabled;&lt;br /&gt;
    //далее идет остальная часть класса, например методы отрисовки&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь, если мы унаследуем некоторый класс от данного класса и переопределим соответствующие методы отрисовки, то у класса потомка так же можно будет использовать свойство &amp;lt;tt&amp;gt;enabled&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var myForm = new Form; //создаем окно&lt;br /&gt;
var myButton = Button.CreateAtPos(myForm, 10, 10); //добавляем кнопку&lt;br /&gt;
myButton.caption = &amp;quot;Click me!&amp;quot;; //устанавливаем подпись&lt;br /&gt;
myButton.OnClick += { |x| x.enabled = false; }; //подключаем обработчик события&lt;br /&gt;
myForm.Show(); //показываем окно&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Приведенный выше код создаст окно и разместит на нем кнопку (подразумевается, что класс &amp;lt;tt&amp;gt;Button&amp;lt;/tt&amp;gt; унаследован от нашего класса &amp;lt;tt&amp;gt;Widget&amp;lt;/tt&amp;gt;). Затем устанавливаются свойства кнопки, такие как подпись и [[Блоки|блок]] обработчика события &amp;lt;tt&amp;gt;OnClick&amp;lt;/tt&amp;gt;. При нажатии на кнопку она станет неактивной.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
В заключение, кратко опишем синтаксис объявления свойства и поясним его. Итак, объявление любого свойства начинается с указания ключевого слова &amp;lt;tt&amp;gt;'''property'''&amp;lt;/tt&amp;gt;, после которого идет [[идентификатор]] типа свойства. Тип может быть опущен, тогда для свойства будет определен [[Переменные#Нетипированные (динамические) переменные|динамический тип]]. Затем указывается идентификатор имени свойства. &lt;br /&gt;
&lt;br /&gt;
Оставшаяся часть зависит от того, какое свойство объявляется:&lt;br /&gt;
&lt;br /&gt;
* Если объявляется свойство на чтение, то указывается ключевое слово &amp;lt;tt&amp;gt;'''read'''&amp;lt;/tt&amp;gt;, после которого идет либо идентификатор имени поля, которое нужно читать, либо имя метода, который должен использоваться как ''аксессор''. В роли аксессора может выступать метод, не принимающий параметров и возвращающий некоторое значение, которое будет возвращаться как значение свойства.&lt;br /&gt;
* Если объявляется свойство на запись, то указывается, соответственно ключевое слово &amp;lt;tt&amp;gt;'''write'''&amp;lt;/tt&amp;gt; после которого идет либо имя поля, которое нужно записывать, либо имя метода, который должен использоваться как ''мутатор''. В качестве мутатора может выступать метод, принимающий один параметр. Возвращаемое значение игнорируется, так что оно может быть любым.&lt;br /&gt;
* Если объявляется свойство, доступное как на чтение так и на запись, то указываются обе части, причем первой идет часть чтения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' Если тип свойства указан явно, то в зависимости от типа поля либо типа возвращаемого значения аксессора, может быть выполнена операция [[Приведение типов|приведения типов]]. Разумеется, если тип поля или результат аксессора неприводим к указанному типу свойства, то будет выдано сообщение об ошибке. Аналогичная ситуация обстоит и с параметром мутатора.&lt;br /&gt;
&lt;br /&gt;
Кратко, синтаксис объявления свойства можно описать в стиле справки к командам оболочки:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
property [тип] &amp;lt;имя&amp;gt; [read &amp;lt;аксессор|поле&amp;gt;] [write &amp;lt;мутатор|поле&amp;gt;];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Расширения ==&lt;br /&gt;
&lt;br /&gt;
Иногда бывает необходимо расширить функциональность некоторого существующего класса без порождения дочернего класса. Это может быть необходимо в тех случаях, когда исходный класс уже используется в коде программы и порождение нового класса нарушило бы спецификацию на интерфейс, либо потребовало значительных изменений в исходных текстах программы. В таких случаях целесообразно применять т. н. ''расширения классов''. Синтаксически, конструкция расширения практически не отличается от конструкции объявления класса, однако методы и свойства перечисленные в нем, дополняются к исходному классу, то есть наследования не происходит.&lt;br /&gt;
&lt;br /&gt;
Как правило, расширения применяются к классам [[Стандартной библиотека Gide|стандартной библиотеки]], либо к [[unmanaged код|неуправляемым классам]].&lt;br /&gt;
&lt;br /&gt;
В качестве примера приведем код, расширяющий функциональность класса &amp;lt;tt&amp;gt;[[Стандартные типы данных#Целые числа|int]]&amp;lt;/tt&amp;gt; с помощью свойства &amp;lt;tt&amp;gt;factorial&amp;lt;/tt&amp;gt;. Расширения объявляются путем указания ключевого слова &amp;lt;tt&amp;gt;'''extend'''&amp;lt;/tt&amp;gt;, после которого указывается [[идентификатор]] имени класса, который следует расширить. Затем идет тело расширения, такое же как при описании классов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
package intmod_fact;&lt;br /&gt;
import std;&lt;br /&gt;
external console_stream STDOUT;&lt;br /&gt;
function void println(const string s) { STDOUT.print(s + &amp;quot;\n&amp;quot;); }&lt;br /&gt;
&lt;br /&gt;
extend int {&lt;br /&gt;
    const function ubigint GetFactorial() {&lt;br /&gt;
        var ubigint result = 1, int x;&lt;br /&gt;
        for (x = this; x &amp;gt; 1; --x)&lt;br /&gt;
            result *= x;&lt;br /&gt;
        return result;&lt;br /&gt;
    }&lt;br /&gt;
    property ubigint factorial read GetFactorial;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
export function main() {&lt;br /&gt;
    println(&amp;quot;Factorial of 10 is &amp;quot; + 10.factorial);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;6-14: Мы объявляем расширение класса &amp;lt;tt&amp;gt;[[Стандартные типы данных#Целые числа|int]]&amp;lt;/tt&amp;gt;, реализованного в [[Стандартная библиотека gide|стандартной библиотеке]]. Добавляется частный метод &amp;lt;tt&amp;gt;GetFactorial()&amp;lt;/tt&amp;gt;, и свойство &amp;lt;tt&amp;gt;factorial&amp;lt;/tt&amp;gt;, связанное с методом. Как видно из названия, метод рассчитывает факториал числа, которое содержится в объекте. В данном контексте, специальная переменная ''this'' имеет тип &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt; и ссылается на сам объект. Таким образом, для числа 10 переменная ''this'' будет равна 10.&lt;br /&gt;
&lt;br /&gt;
;17: Здесь мы видим применение расширения в действии. Константа 10 на момент компиляции преобразуется в [[Константы#Константные объекты|константный объект]] класса &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;, который подобно любому другому объекту этого же класса будет иметь свойство &amp;lt;tt&amp;gt;factorial&amp;lt;/tt&amp;gt;, которое мы и используем. При попытке чтения из этого свойства будет вызван метод &amp;lt;tt&amp;gt;GetFactorial()&amp;lt;/tt&amp;gt;, результат выполнения которого возвращается как значение свойства, то есть как факториал числа. &amp;lt;!--Его мы вызываем с помощью специального синтаксиса, для передачи блока в качестве [[Функции#Аргументы|параметра функции]]. При этом, сам блок указывается прямо в коде вызова функции. Тело блока состоит из одного вызова функции, выводящей текущее число в стандартный поток вывода. --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
: Обратите внимание, что функция &amp;lt;tt&amp;gt;println()&amp;lt;/tt&amp;gt;, принимает в качестве параметра [[Стандартные типы данных#Строки|строку]], в то время как тип свойства определен как &amp;lt;tt&amp;gt;[[Стандартные типы данных#Целые числа|ubigint]]&amp;lt;/tt&amp;gt;. В этом нет ничего странного, потому что класс &amp;lt;tt&amp;gt;ubigint&amp;lt;/tt&amp;gt; имеет [[Типы операторов#Операторы приведения типов|оператор приведения типа]] к классу &amp;lt;tt&amp;gt;[[Стандартные типы данных#Строки|string]]&amp;lt;/tt&amp;gt;, который вызывается компилятором автоматически. Таким образом, при вычислении значения выражения в скобках, сперва значение факториала ''приводится'' к типу строки, которая складываясь со строкой слева от оператора &amp;lt;tt&amp;gt;+&amp;lt;/tt&amp;gt; передается в качестве параметра функции.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' При работе с расширениями существует одно важное ограничение. Расширять классы можно только методами и свойствами, но не полями. Это связано с внутренней организацией языка К++ и виртуальной машины. Дополнительно стоит отметить, что методы объявленные в расширении будут перекрывать соответствующие им методы класса (имеется в виду ситуация когда имена и наборы параметров полностью совпадают). Важно понимать, что такое перекрытие не является объявлением виртуального метода — происходит именно замещение старого метода новым. &lt;br /&gt;
&lt;br /&gt;
== Смотри также ==&lt;/div&gt;</summary>
		<author><name>KroTozeR</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%9A%D0%BB%D0%B0%D1%81%D1%81%D1%8B_%D0%B8_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B</id>
		<title>Классы и объекты</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%9A%D0%BB%D0%B0%D1%81%D1%81%D1%8B_%D0%B8_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B"/>
				<updated>2007-10-05T11:17:19Z</updated>
		
		<summary type="html">&lt;p&gt;KroTozeR: /* История развития ООП */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== История развития ООП ==&lt;br /&gt;
&lt;br /&gt;
Для того чтобы понять, что же такое классы и объекты, сперва необходимо проследить историю развития программирования. А конкретнее, историю возникновения концепции ООП. Автор верит, что знание истории возникновения тех или иных мыслей и идей может помочь читателю осознать необходимость нововведений, и главное — их преимуществ перед существовавшими в то время решениями.&lt;br /&gt;
&lt;br /&gt;
=== Возникновение языков программирования ===&lt;br /&gt;
&lt;br /&gt;
На заре зарождения вычислительных машин их приходилось программировать поистине &amp;quot;вручную&amp;quot;. Все, что было в руках  программиста это пульт управления ЭВМ. На шестнадцатеричной клавиатуре (а еще раньше на пульте с тумблерами) программист задавал некоторый адрес ячейки памяти, затем он мог либо выполнить операцию чтения — тогда на табло появлялись цифры, соответствующие значению ячейки памяти, либо операцию записи — при этом, по указанному адресу записывалось значение, набранное на клавиатуре данных. Затем, программист переходил к следующей ячейке, и так повторялось до тех пор, пока в память ЭВМ не была внесена вся программа. На программистах (точнее, на операторах ЭВМ) лежала огромная ответственность! Одна ошибка, один неверно установленный переключатель или одна пропущенная команда неминуемо вели к ошибкам в работе программы, а, следовательно, и к ошибкам в расчетах. Могли потребоваться недели, и даже месяцы на поиск этой ошибки и на ее исправление! Естественно, ни о каких языках программирования тогда не могло идти и речи.&lt;br /&gt;
&lt;br /&gt;
=== Появление ассемблера ===&lt;br /&gt;
&lt;br /&gt;
Впоследствии, программисты смекнули, что команды можно записывать в виде мнемонических обозначений или мнемоник — то, что раньше применялось только для удобства записи на бумаге — было стандартизировано и приспособлено как ''язык'' общения человека и ЭВМ. Так появился первый язык программирования — ''язык ассемблера''. Конечно, языком его можно назвать с некоторой натяжкой, ведь он не обеспечивал и десятой доли тех возможностей (вроде автоматического разбора арифметических выражений), которые мы привыкли ассоциировать с языками программирования. Тем не менее, ассемблер выполнял свою главную и основную функцию — избавлял программиста от необходимости работать с памятью (и адресами) напрямую. Вместо этого, программист записывал свои команды в стандартной форме, понятной ЭВМ. Далее выполнялась программа ''транслятор'', которая преобразовывала исходный текст программы в поток машинных команд, которые уже можно исполнять.&lt;br /&gt;
&lt;br /&gt;
=== Концепция языка высокого уровня ===&lt;br /&gt;
&lt;br /&gt;
...С увеличением сложности программ, программировать на ассемблере становилось все сложнее и сложнее.  Ввиду естественных ограничений человеческой памяти и внимания, написание программ и их отладка стали настолько сложными, что люди всерьез подошли к рассмотрению идеи языка высокого уровня — некоторой системы обозначений и абстрактных команд, которая позволила бы записывать программы в абстрактной форме, не заботясь о том, как располагать в памяти код и данные, как их структурировать и т. д. Всю эту работу брал на себя компилятор. Кроме того, он обеспечивал программиста удобным способом записи математических выражений — в естественной форме. При этом, компилятор сам &amp;quot;разворачивал&amp;quot; эти выражения в наборы инструкций ассемблера, попутно подставляя значения констант и адреса переменных. Это дало возможность программистам записывать формулы вычислений в натуральном виде, что уменьшало трудозатраты, ускоряло написание программ и уменьшало вероятность ошибок. Тем не менее, многие авторитеты того времени очень негативно отзывались о языках высокого уровня. В то время языки были довольно несовершенными и генерировали &amp;quot;ужасный&amp;quot; с точки зрения программистов код. Код был не оптимален, занимал огромное по тем временам количество памяти и работал медленнее, чем та же программа, написанная на ассемблере. Смешно сказать, но в то время многие не верили в то, что будущее за ЯП высокого уровня; их считали не более чем игрушкой для &amp;quot;чайников&amp;quot;, возжелавших вообразить себя настоящими программистами. &lt;br /&gt;
&lt;br /&gt;
Но время шло, количество приверженцев нового подхода постоянно увеличивалось. Сами же компиляторы становились все более мощными и генерировали все более компактный и оптимальный код. Дошло до того, что компилятор с оптимизатором в некоторых случаях генерировал код, более качественный, чем это делал программист. С этого момента ЯП высокого уровня заняли свое место в истории и в инструментарии любого разработчика.&lt;br /&gt;
&lt;br /&gt;
=== Структурное программирование ===&lt;br /&gt;
&lt;br /&gt;
С развитием языков программирования появились новые концепции и новые парадигмы программирования. От линейного моноблочного программирования, при котором программа писалась единым &amp;quot;куском&amp;quot; от начала до конца, перешли к программам модульным и структурным. При них программа представляла уже совокупность процедур (функций), которые вызывали друг друга в ходе работы программы. Процедуры представляли собой подпрограммы, решающие отдельные частные задачи. При этом код получался более читаемым, и облегчалась его отладка. &lt;br /&gt;
&lt;br /&gt;
Опять же, в ходе усложнения решаемых задач и, вследствие этого, увеличения количества переменных с которыми приходилось работать программисту, возникла идея группировки некоторых переменных в группы или структуры. Структуры формировались по назначению и содержали в себе переменные, имеющие отношение к одной и той же сущности. Это значительно повысило читаемость программ и уменьшило количество ошибок в них.&lt;br /&gt;
&lt;br /&gt;
=== Объектно-ориентированное программирование ===&lt;br /&gt;
&lt;br /&gt;
Ну и наконец, одна светлая голова додумалась до мысли: &amp;quot;а что если в структурах группировать не только переменные, но и сами процедуры которые должны работать с этими переменными?&amp;quot;. В результате получилось то, что мы сейчас называем классом — то есть, некоторая обособленная функциональная сущность, которая сама хранит свои данные, а главное сама умеет их обрабатывать. Теперь программисту не нужно помнить, какая из процедур отвечает за некоторое действие над такими-то переменными — он просто берет объект и работает с ним. Все что происходит с объектом внутри — это его личное дело.&lt;br /&gt;
&lt;br /&gt;
Последним шагом к современному пониманию программ явились концепции [http://ru.wikipedia.org/wiki/Полиморфизм_(программирование) полиморфизма], [http://ru.wikipedia.org/wiki/Инкапсуляция_(программирование) инкапсуляции] и [http://ru.wikipedia.org/wiki/Наследование_(программирование) наследования]. Не будем пока углубляться в суть этих понятий, отметим только, что их введение сформировало современное понимание объектно-ориентированного программирования.&lt;br /&gt;
&lt;br /&gt;
При написании программы на объектно-ориентированном языке, программист строит математическую модель взаимодействия различных сущностей. Каждая из сущностей это свой мир, у которого есть свои законы и особенности. При этом сущности могут быть как конкретные, вроде &amp;quot;сетевой интерфейс&amp;quot; или &amp;quot;файл&amp;quot;, так и совершенно абстрактные, например &amp;quot;отношение&amp;quot; или &amp;quot;ошибка&amp;quot;. Программист описывает каждую из сущностей в отдельности, обособлено от остальных. Вся необходимая для работы информация хранится внутри, а для взаимодействия с внешним миром предусмотрен ''интерфейс'' — некоторая совокупность ''свойств'' данной сущности (отражающих ее внутреннее состояние) и способов взаимодействия с ней — ''методов''.&lt;br /&gt;
&lt;br /&gt;
В ходе работы программы сущности могут взаимодействовать, читая и записывая свойства и вызывая методы друг друга, использовать друг друга как подсистемы, порождать новые сущности и т. д. Получается, что при написании программы, программист переносит свое внутреннее представление того как он видит эту программу, то из чего она состоит и как отдельные ее части взаимодействуют. Теперь не приходится адаптировать свое понимание проблемы к конкретным инструментальным средствам и возможностям языка программирования (конечно, это все же происходит, но уже гораздо менее заметно).&lt;br /&gt;
&lt;br /&gt;
В терминах современных языков программирования такие сущности называются ''классами'', в смысле ''классами сущностей''. А отдельные представители этих классов называются ''экземплярами'', ''инстанциями'' (на английский манер) или ''объектами''. Более подробно, различие между классами и объектами будет рассмотрено ниже.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Итак, любой современный объектно-ориентированный язык оперирует понятиями классов и объектов. Точно такой же подход нашел свое применение в нашей виртуальной машине. Основой всей платформы Gide является объектно-ориентированный принцип. Причем, в этом смысле она является более объектно-ориентированной, нежели традиционные ЯП вроде C++. В C++ существуют понятия элементарных типов. Это сделано в целях производительности и было продиктовано архитектурой самого языка. В классических языках программирования, элементарные типы, так или иначе, отражают сущности из &amp;quot;реального мира&amp;quot;. Например, целочисленные типы int и short соответствуют 32х и 16ти разрядным регистрам процессора, указатели и строки соответствуют представлению данных в памяти и т. д. В Gide это не так. Все с чем оперирует виртуальная машина — это объекты. Соответственно, не существует понятия элементарных типов (просто нет критерия, который бы позволил отделить одно от другого). &lt;br /&gt;
&lt;br /&gt;
Язык K++ в полной мере наследует идеологию Gide. Скажем, для него нет отличия между типом &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt; (целое число) и некоторым пользовательским классом &amp;lt;tt&amp;gt;MyWeirdClass&amp;lt;/tt&amp;gt;: везде, где можно использовать &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;, можно использовать &amp;lt;tt&amp;gt;MyWeirdClass&amp;lt;/tt&amp;gt; и наоборот. Более того, это позволяет работать с системными классами так же, как с пользовательскими! Например, ничто не мешает унаследовать свой класс от класса &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;, равно как ничто не мешает определить математические операторы для класса &amp;lt;tt&amp;gt;MyWeirdClass&amp;lt;/tt&amp;gt; и использовать объекты этого класса в арифметических выражениях. При этом изменится логика работы всего языка. К примеру, после добавления некоторого метода к классу int можно будет вызывать методы у всех его экземпляров, даже тех, что представлены числовыми константами внутри самого языка!&lt;br /&gt;
&lt;br /&gt;
== Понятие класса ==&lt;br /&gt;
&lt;br /&gt;
Что такое ''класс'' проще всего объяснить на примерах. Представьте, что вас спрашивают &amp;quot;что такое яблоко?&amp;quot;. Скорее всего, вы ответите что-то вроде: &amp;quot;яблоки, это вкусные плоды растущие на деревьях — яблонях; они бывают разных цветов и размеров&amp;quot;. Заметьте, что когда мы описываем ''яблоки как понятие'', мы не имеем в виду некоторый конкретный объект, а скорее описываем наше обобщенное представление о них. Если же вас попросят описать совершенно конкретное яблоко, лежащее на блюдечке перед вами, вы будете говорить о нем по другому: &amp;quot;это яблоко, оно красное, сочное, судя по всему спелое. с черенком, на котором остался листик, и маленькой червоточинкой&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Разница заключается в том, что когда вы говорили ''о яблоках'', вы описывали свое представление яблок, как ''класса'' объектов. Когда вы описывали ''яблоко'', то вы имели в виду конкретный ''экземпляр'', или ''объект''. Говоря о классе, вы можете описать только те свойства, что принадлежат всем яблокам; когда же вы описываете объект, то в первую очередь имеете в виду его индивидуальные особенности (свойства). Тем не менее, описание объекта начинается с упоминания его класса (&amp;quot;это яблоко,...&amp;quot;), а затем уже свойств объекта (ведь &amp;quot;сочным и спелым&amp;quot; может быть и апельсин). Это важная особенность объектно-ориентированного подхода. &lt;br /&gt;
&lt;br /&gt;
Другой пример: если вас попросить &amp;quot;представьте дерево&amp;quot;, то вы либо представите некоторое совершенно абстрактное, усредненное дерево, либо попросите уточнить, какое именно дерево имеется в виду. Ваше сознание из имеющейся информации смогло уяснить только самые общие сведения о классе. Но этой информации не достаточно, для более детального описания. Это тоже важно, поскольку в этом простом примере кроется сущность механизма наследования — постепенного уточнения классами-потомками общих черт своих предков. Таким образом, и яблоня и груша — деревья. Но яблони отличаются от груш. Получается, что классы ''яблони'' и ''груши'' имеют общего предка — класс ''дерево''.&lt;br /&gt;
&lt;br /&gt;
Таким образом, понятия классов и объектов это не математическая абстракция, а скорее часть нашего восприятия мира, того как мы мыслим.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из примеров выше мы смогли уяснить следующее:&lt;br /&gt;
&lt;br /&gt;
* Классы, это некоторые абстрактные сущности, задающие общие черты своих объектов&lt;br /&gt;
* Все объекты одного класса похожи друг на друга, но имеют некоторые индивидуальные особенности&lt;br /&gt;
* Классы могут наследоваться, расширяя набор свойств класса родителя своими собственными&lt;br /&gt;
&lt;br /&gt;
Перейдем теперь ближе к основной теме нашего повествования, а именно языку К++:&lt;br /&gt;
&lt;br /&gt;
С точки зрения языка, ''класс'' представляет собой набор следующих элементов:&lt;br /&gt;
* ''полей'', т.е. переменных, хранящих индивидуальные особенности объектов, &lt;br /&gt;
* ''методов'', т.е. функций, определяющих поведение данного объекта;&lt;br /&gt;
* ''свойств'', определяющих взаимодействие других объектов с объектами данного класса.&lt;br /&gt;
&lt;br /&gt;
''Поля'' — это переменные, которые относятся к некоторому конкретному экземпляру нашего класса. Каждый экземпляр имеет свою копию набора переменных, таким образом они могут хранить свое состояние (например показатель &amp;quot;спелости&amp;quot;, в примере с яблоками). Эти переменные доступны только самому классу, доступ извне для них запрещен. Для того, чтобы частично разрешить этот доступ, применяются ''свойства''. Сами свойства будут описаны позже, здесь стоит отметить только то, что свойство может быть доступно &amp;quot;только на чтение&amp;quot;, &amp;quot;только на запись&amp;quot; или &amp;quot;и на чтение и на запись&amp;quot;. Свойство может быть связано либо с некоторым полем, либо с методом. Например, если свойство доступно &amp;quot;только на чтение&amp;quot; то его можно использовать для получения значения, но не для его записи (то есть, такое свойство не может фигурировать в качестве [[lvalue]]).&lt;br /&gt;
&lt;br /&gt;
''Методы'' — это тот самый, связанный с данными код (вспомните [[Классы и объекты#История развития ООП|историю ООП]]) который, естественно, может работать с переменными объекта (то есть с полями) и служит для описания поведения данного класса объектов.&lt;br /&gt;
&lt;br /&gt;
Класс может иметь одного или нескольких родителей (опять же, подробнее об этом см. ниже)&lt;br /&gt;
&lt;br /&gt;
Методы и свойства класса могут находиться в различных областях видимости. Это обеспечивается с помощью [[Спецификаторы доступа|спецификаторов доступа]]:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''private'''&amp;lt;/tt&amp;gt; — Частная собственность! Видимость только внутри методов данного класса&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''protected'''&amp;lt;/tt&amp;gt; — &amp;quot;Семейная реликвия&amp;quot;, доступ внутри методов данного класса и всех его дочерних классов&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''public'''&amp;lt;/tt&amp;gt; — видимость и доступ для всех&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' По умолчанию методы имеют видимость &amp;lt;tt&amp;gt;'''private'''&amp;lt;/tt&amp;gt;, в то время как свойства — &amp;lt;tt&amp;gt;'''public'''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Приведем наконец пример объявления класса:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
class MyWeirdClass {&lt;br /&gt;
    var m_x = 0;  // поле m_x, изначально проинициализированное нулем&lt;br /&gt;
    const m_y = 1; // поле-константа m_y&lt;br /&gt;
&lt;br /&gt;
    // методы класса&lt;br /&gt;
    public const function int get_mul() { return m_x * m_y; }&lt;br /&gt;
    public function void set_mul(int x) { m_x = x / m_y; }&lt;br /&gt;
&lt;br /&gt;
    // свойство класса&lt;br /&gt;
    public property mul read get_mul write set_mul;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;1: Как у любого нормального разумного существа, у класса есть &amp;quot;голова&amp;quot; и &amp;quot;тело&amp;quot;. Ключевое слово &amp;lt;tt&amp;gt;'''class'''&amp;lt;/tt&amp;gt; начинает объявление класса. Далее за ним следует [[идентификатор]] имени класса, после чего идет тело класса.&lt;br /&gt;
&lt;br /&gt;
;3-4: Здесь мы видим объявление двух полей класса — переменной ''m_x'' и константы ''m_y'', которые, подобно обычным переменным инициализируются тут же, на месте объявления (камень в огород C++). Зачем нужны поля-константы, описано в главе [[Константы]]. &lt;br /&gt;
&lt;br /&gt;
;7-8: Для доступа к состоянию объекта, определены два метода: ''аксессор'' &amp;lt;tt&amp;gt;get_mul()&amp;lt;/tt&amp;gt; и ''мутатор'' &amp;lt;tt&amp;gt;set_mul()&amp;lt;/tt&amp;gt;. Подобные конструкции применяются настолько часто, что им были даны специальные имена. Как видно из названия, первый метод дает доступ к значению, второй изменяет или мутирует его.&lt;br /&gt;
&lt;br /&gt;
;11: Завершается объявление класса объявлением свойства ''mul'', которое связывается с аксессором и мутатором. Думаю, читатель уже догадался, что это свойство типа &amp;quot;чтение и запись&amp;quot;. Таким образом, при обращении к свойству на чтение, будет вызыан аксессор, а результат его выполнения будет возвращен в качсетве значения свойства. И наоборот, при попытке записать в свойство некоторое значение, будет вызван мутатор, в качестве аргумента которому будет передано это самое значение, а уж сам мутатор позаботится о том чтобы оно было &amp;quot;доставлено по адресу&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
: '''Примечание:''' Зачем нужны такие сложности и зачем дублировать вроде бы одинаковый функционал, будет описано ниже.&lt;br /&gt;
&lt;br /&gt;
== Понятие объекта ==&lt;br /&gt;
&lt;br /&gt;
Собственно, понятие объекта уже много раз было затронуто выше по повествованию. Поэтому здесь приведем лишь небольшое определение: Под ''объектом'' подразумевается экземпляр того или иного класса, т.е. некоторая сущность, поведение которой задается соответствующим классом.&lt;br /&gt;
&lt;br /&gt;
Для создания объекта того или иного класса служит оператор &amp;lt;tt&amp;gt;'''new'''&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
    var myWeirdObject = new MyWeirdClass;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь мы видим типичную конструкцию объявления переменной, однако в инициализаторе переменной находится всего один оператор, за которым следует [[идентификатор]] имени класса, экземпляр которого мы хотим создать.&lt;br /&gt;
&lt;br /&gt;
== Наследование ==&lt;br /&gt;
&lt;br /&gt;
Под ''наследованием'' классов понимается механизм такого создания (объявления) класса, при котором он расширяет функционал одного или нескольких уже существующих классов (родителей). Вспомните пример с деревьями. Когда мы говорим, что класс ''яблоня'' наследуется от класса ''дерево'' — это значит что ''яблоня'' унаследует все свойства своего класса-родителя, некоторые из которых он может изменить, ну и дополнить своими собственными свойствами. Опыт нам подсказывает, что у любого дерева есть листья (для простоты не будем вспоминать про хвойные), однако не любое дерево плодоносит яблоками. Если же рассмотреть сами яблоки, то можно сказать, что класс ''яблоко'' унаследован от класса ''фрукт'', который определяет что фрукты (и соответственно яблоки) должны расти на деревьях.&lt;br /&gt;
&lt;br /&gt;
Таким образом, наследование гарантирует, что к дочерним классам применимы все операции, доступные в родительском классе: любой алгоритм, работающий с объектами родительского класса, может работать с объектами его дочерних классов. &lt;br /&gt;
&lt;br /&gt;
Для задания наследования, в объявлении класса следует указать ключевое слово &amp;lt;tt&amp;gt;'''extends'''&amp;lt;/tt&amp;gt;,  за которым необходимо перечислить список идентификаторов классов-родителей, разделяя их запятыми:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
// коробка&lt;br /&gt;
class Box { &lt;br /&gt;
    // из чего сделана коробка?&lt;br /&gt;
    public const function string material() { return &amp;quot;Картон&amp;quot;; }&lt;br /&gt;
&lt;br /&gt;
    // что в коробке?&lt;br /&gt;
    public const function string contents() { return &amp;quot;Пусто&amp;quot;; }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// коробка с картошкой&lt;br /&gt;
class BoxWithPotatoes extends Box { &lt;br /&gt;
    public const function string contents() { return &amp;quot;Картошка&amp;quot;; }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function OutputBox(const Box b) {&lt;br /&gt;
    STDOUT.print(&amp;quot;Материал: &amp;quot; + b.material() + &amp;quot;, содержит: &amp;quot; + b.contents() + &amp;quot;\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function main() {&lt;br /&gt;
    var b1 = new Box;&lt;br /&gt;
    var b2 = new BoxWithPotatoes;&lt;br /&gt;
    OutputBox(b1); // Материал: Картон, содержит: Пусто&lt;br /&gt;
    OutputBox(b2); // Материал: Картон, содержит: Картошка&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;2-7: В этом примере мы создаем класс &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt;, который представляет собой некоторую коробку. Мы определяем ее свойства, такие как ''материал'' и ''содержимое''.&lt;br /&gt;
&lt;br /&gt;
;10-12: Далее мы определяем класс &amp;lt;tt&amp;gt;BoxWithPotatoes&amp;lt;/tt&amp;gt; (''коробка с картошкой''), который наследуется от класса &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt;, и тем самым заимствует свойства материала и содержимого, но первое он переопределяет (в случае методов это называется ''перекрытием'') собственным методом.&lt;br /&gt;
&lt;br /&gt;
;14-16: Мы определяем некоторую [[Функции|функцию]] для работы с нашими классами, которая будет отображать их состояние. Заметьте, что в качестве [[Функции#Аргументы|аргумента функции]] передается экземпляр класса &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt;, то есть класса-родителя. При этом, мы предполагаем что любой класс, унаследованный от базового класса, будет обладать необходимым нам интерфейсом, а именно методами получения информации о свойствах (аксессорами мы их не называем, потому что они не связаны с конкретным полем; это было бы неверно).&lt;br /&gt;
&lt;br /&gt;
;18-23: Объявляется функция &amp;lt;tt&amp;gt;main()&amp;lt;/tt&amp;gt;, внутри которой и происходит самое интересное. Сначала мы создаем два экземпляра ''b1'' и ''b2'' классов &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt; и &amp;lt;tt&amp;gt;BoxWithPotatoes&amp;lt;/tt&amp;gt; соответственно. А затем, вызываем вышеописанную функцию &amp;lt;tt&amp;gt;OutputBox()&amp;lt;/tt&amp;gt;, которая отображает содержимое. Вывод в терминал (написан в комментарии к вызову) показывает как это все работает.&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' при использовании множественного наследования существует одно серьезное ограничение: его нельзя применять для наследования от классов стандартной библиотеки. Это ограничение связано с архитектурой платформы Gide. Однако, его можно обойти с помощью создания [[Класс-обертка|классов-оберток]] для системного класса, с последующим наследованием от него нового класса.&lt;br /&gt;
&lt;br /&gt;
== Методы ==&lt;br /&gt;
&lt;br /&gt;
''Метод'' — это некоторый код, связанный с объектом и управляющий его поведением. Управление может заключаться в изменении переменных постояния объекта (полей), либо выполнением некоторых операций над ними.&lt;br /&gt;
&lt;br /&gt;
При объявлении метода могут быть указаны следующие ключевые слова, в указанном порядке:&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''private'''&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;'''protected'''&amp;lt;/tt&amp;gt; или &amp;lt;tt&amp;gt;'''public'''&amp;lt;/tt&amp;gt; — определяют область видимости метода&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''static'''&amp;lt;/tt&amp;gt; — указывает, что метод является ''статическим'' (см. ниже)&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''const'''&amp;lt;/tt&amp;gt; — метод не изменяет объект&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''function'''&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;'''operator'''&amp;lt;/tt&amp;gt; или &amp;lt;tt&amp;gt;'''constructor'''&amp;lt;/tt&amp;gt; указывает, что объявляется: ''метод'', ''[[Операторы|оператор]]'' или ''конструктор'' (см. ниже)&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''const'''&amp;lt;/tt&amp;gt; — метод возвращает результат, который нельзя изменять&lt;br /&gt;
&lt;br /&gt;
После этого указывается тип, возвращаемый методом. Если он опущен — возвращается [[Переменные#Нетипированные (динамические) переменные|динамическая переменная]]; если вместо типа указано ключевое слово &amp;lt;tt&amp;gt;'''void'''&amp;lt;/tt&amp;gt; — метод не возвращает результата. Следом за типом идет имя метода, затем — перечисление [[Функции#Аргументы|аргументов]] в скобках. Подробнее об объявлении функций и передаче параметров, можно прочитать в главе [[Функции]].&lt;br /&gt;
&lt;br /&gt;
Тело метода может быть объявлено как непосредственно в теле класса, так и вынесено за его пределы, например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
class MyClass {&lt;br /&gt;
    public const function string F1() { return &amp;quot;smth&amp;quot;; }&lt;br /&gt;
    public const function string F2();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function string MyClass::F2() {&lt;br /&gt;
    return F1();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;6: При вынесении функции за пределы класса, имя соответствующего метода предворяется именем класса из которого он был вынесен; имена отделяются друг от друга символом &amp;quot;двойное двоеточие&amp;quot; ( &amp;lt;tt&amp;gt;::&amp;lt;/tt&amp;gt; ); дополнительно — в заголовке вынесенной функции необходимо указать тип возвращаемого значения и параметры функции, все остальные ключевые слова указывать не обязательно.&lt;br /&gt;
&lt;br /&gt;
;7: В теле метода доступны все поля, методы и свойства данного класса и его предков. Например, в коде приведенном выше, метод &amp;lt;tt&amp;gt;F2()&amp;lt;/tt&amp;gt; вызывает метод &amp;lt;tt&amp;gt;F1()&amp;lt;/tt&amp;gt; для того же объекта.&lt;br /&gt;
&lt;br /&gt;
=== Статические методы ===&lt;br /&gt;
&lt;br /&gt;
''Статический метод класса'' — это метод, относящиеся к данному классу, но не объекту этого класса. Т.е. это некоторая вспомогательная для данного класса функция.&lt;br /&gt;
&lt;br /&gt;
При объявлении статического метода нужно указать ключевое слово &amp;lt;tt&amp;gt;'''static'''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В теле статического метода нет возможности напрямую обращаться к другим методам данного класса, т.к. статическому методу недоступен объект класса. Фактически, единственным отличием статического метода от обычной функции является то, что такой метод может обращаться к защищенным полям и методам класса некоторого другого объекта. Подобный подход широко применяется при написании ''конструкторов'' (см. ниже).&lt;br /&gt;
&lt;br /&gt;
Пример:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
class MyClass {&lt;br /&gt;
    public static function string Info() { return &amp;quot;Я MyClass!&amp;quot;; }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function f() {&lt;br /&gt;
    // Вызов статического метода:&lt;br /&gt;
    var myClassInfo = MyClass.Info();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Конструкторы ===&lt;br /&gt;
&lt;br /&gt;
В ходе написания программы часто приходится создавать новые объекты. При этом, объекту требуется установить некоторое начальное состояние. Разумеется, это выполняется либо путем написания инициализаторов соответствующих полей, либо занчения полям присваиваются явным образом. Но что делать, если объект может иметь несколько начальных состояний? То есть, в зависимости от некоторых условий, одним и тем же полям объекта могут быть присвоены различные наборы значений. Тут уже одними инициализаторами не обойтись. Присваивать значения можно прямо в коде программы, однако это не очень красивое решение, поскольку один и тот же объект может создаваться в нескольких местах программы и придется копировать один и тот же участок кода, инициализирующий поля объекта. Недостаток этого подхода в том, что при большом количестве полей, программист может забыть проинициализировать некоторе поле, либо при изменении условий инициализации он может изменить их только в одном месте программы, забыв что объект может создаваться и в других местах. Более разумным является подход, при котором программист пишет функцию, инициализирующую поля объекта. При этом, весь код собирается в одном месте и вероятность ошибок значительно понижается. &lt;br /&gt;
&lt;br /&gt;
Конструкторы развивают эту идею, дополняя код инициализации полей кодом создания самого экземпляра объекта. То есть, в конструкторе собирается весь код относящийся к созданию инстанции класса. Итак, ''конструктор класса'' — это специальный метод, инициализирующий объект класса. С точки зрения языка, конструктор — это статический метод класса, возвращающий экземпляр данного класса.&lt;br /&gt;
&lt;br /&gt;
Таким образом, следующие объявления в рамках класса эквивалентны:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
public constructor Create();&lt;br /&gt;
public static MyClass Create();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тело конструктора чаще всего выглядит следующим образом: сначала создается экземпляр класса при помощи оператора &amp;lt;tt&amp;gt;'''new'''&amp;lt;/tt&amp;gt;, затем производятся некоторые действия, инициализующие этот объект, и, наконец, этот объект возвращается в качестве результата. &lt;br /&gt;
&lt;br /&gt;
В качестве примера приведем пример реализации некоторого абстрактного класса &amp;lt;tt&amp;gt;MyStream&amp;lt;/tt&amp;gt;, использующего системную реализацию класса &amp;lt;tt&amp;gt;stream&amp;lt;/tt&amp;gt;, и определяющую собственный конструктор:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
class MyStream {&lt;br /&gt;
    var string m_URL;&lt;br /&gt;
    var stream m_Stream;&lt;br /&gt;
public:&lt;br /&gt;
    static const MODE_READ = 1;&lt;br /&gt;
    static const MODE_WRITE = 2;&lt;br /&gt;
    constructor open(const string url, int mode) {&lt;br /&gt;
        var self = new MyStream;&lt;br /&gt;
        self.m_Stream.open(url, mode);&lt;br /&gt;
        self.m_URL = url;&lt;br /&gt;
        return self;&lt;br /&gt;
    }&lt;br /&gt;
    // прочие методы (опущены для краткости)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;2-3: Объявляются поля ''m_URL'' и ''m_Stream'' нашего класса, которые будут инициализироваться в конструкторе. &lt;br /&gt;
&lt;br /&gt;
;5-6: В публичной области класса объявляются статические константы ''MODE_READ'' и ''MODE_WRITE'', которые задают желаемый режим доступа к открываемому потоку. Это единственный случай, когда поле класса доступно на прямой доступ извне.&lt;br /&gt;
&lt;br /&gt;
;7: Объявляется конструктор &amp;lt;tt&amp;gt;open()&amp;lt;/tt&amp;gt;, принимающий в качестве параметров [[URL]] ресурса который требуется открыть и число, задающее с помощью вышеописанных констант режим доступа к потоку. В теле конструктора мы создаем инстанцию ''self'' нашего класса. Затем производится попытка открытия потока ''m_Stream'': если операция пройдет успешно, то происходит инициализация оставшегося поля ''m_URL'' и выход из конструктора с возвратом созданной инстанции; если же операция открытия потока провалится, то будет сгенерировано ''[[Обработка исключений|исключение]]'' и выполнение конструктора прекратится (управление будет передано &amp;quot;наверх&amp;quot;, вызывающему коду).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Использовать наш класс можно примерно так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;var data = MyStream.open(&amp;quot;http://www.deeptown.org/index.html&amp;quot;, MyStream.MODE_READ);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на второй параметр функции, где мы передаем константу ''MODE_READ'', объявленную внутри самого класса. Подобный подход, когда константы используемые при работе с классом инкапсулируются в тело класса, помогает сконцентрировать код в одном месте и избежать многих ошибок. В результате повышается читаемость кода и не возникает конфликта имен констант.&lt;br /&gt;
&lt;br /&gt;
== Поля ==&lt;br /&gt;
&lt;br /&gt;
Поле класса — это некоторый объект, используемый объектом данного класса.&lt;br /&gt;
&lt;br /&gt;
Объявление поля начинается с одного из трех ключевых слов:&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''var'''&amp;lt;/tt&amp;gt;  — объявление &amp;quot;обычного&amp;quot; поля;&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''const'''&amp;lt;/tt&amp;gt; — данное поле является константой и не может быть изменено;&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''mutable'''&amp;lt;/tt&amp;gt; — значение данного поля не влияет на состояние объекта, и его можно менять даже в методах, объявленных константными.&lt;br /&gt;
&lt;br /&gt;
За ключевым словом следует тип поля и [[идентификатор]] его имени. Тип поля может быть опущен. После имени может стоять символ &amp;quot;=&amp;quot; и выражение, инициализирующее значение данного поля. В целом, синтаксис тот же, что и при объявлении обычной переменой или константы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var int m_x;&lt;br /&gt;
const m_y = 0;&lt;br /&gt;
var m_stream = new stream;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тип поля определяется по следующим правилам:&lt;br /&gt;
* если тип указан явно, ничего определять не надо;&lt;br /&gt;
* если тип не указан, но при объявлении использован инициализатор — типом становится тип результата инициализатора;&lt;br /&gt;
* в противном случае, для поля устанавливается [[Переменные#Нетипированные (динамические) переменные|динамический тип]].&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' В K++ доступ к полям имеет только объект класса — т.е. фактически, все поля находятся в закрытой (private) области видимости. Для предоставления внешним классам доступа к полям следует использовать ''свойства'' (см. ниже).&lt;br /&gt;
&lt;br /&gt;
== Свойства ==&lt;br /&gt;
&lt;br /&gt;
''Свойства'' — это специальные конструкции языка К++, которые позволяют совмещать обращение к данным с вызовом определенного метода. Смысл свойств заключается в том, чтобы программист мог контролировать процесс изменения состояния объекта и своевременно реагировать на это изменение. Свойства бывают доступны на чтение, на запись, или на чтение и на запись одновременно. Это связано с тем, что некоторые свойства объекта (в естественном понимании этого слова), могут предполагать только получение информации о них, другие же могут подразумевать изменение состояния, без возможности чтения. &lt;br /&gt;
&lt;br /&gt;
В существующих языках программирования, таких как C++ тот же функционал реализуется с помощью вызова специальных методов: ''аксессоров'' и ''мутаторов'', которые используются для получения сведений о некотором свойстве или для записи соответственно. Однако, это делает код менее читаемым, особенно в случае мутаторов. Свойства же, позволяют работать с собой подобно обычным полям или объектам, используя операторы. &lt;br /&gt;
&lt;br /&gt;
Приведем два примера, которые позволят понять смысл свойств и их отличие от обычных полей класса.&lt;br /&gt;
&lt;br /&gt;
Предположим, что у нас есть класс, отвечающий за чтение состояния некоторого устройства. Допустим, состояние представляется целым числом и должно определяться по мере обращения. Если бы мы писали на языке C++, то мы оформили бы это в виде метода:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
class MyDevice {&lt;br /&gt;
    int GetState();&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Везде, где нам потребовалось бы читать состояние устройства мы должны были писать что-то типа:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int current_state = Device.GetState();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В случае с К++, чтение свойств осуществляется подобно обычным полям. Перепишем вышеописанный пример на язык К++: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
class MyDevice {&lt;br /&gt;
    function int GetState();&lt;br /&gt;
    property int state read GetState;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Соответственно, обращение к свойству состояния будет выглядеть так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var current_state = Device.state;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При обращении к свойству &amp;lt;tt&amp;gt;state&amp;lt;/tt&amp;gt;  будет автоматически вызыван метод &amp;lt;tt&amp;gt;GetState()&amp;lt;/tt&amp;gt;, результат которого будет возвращен как значение свойства. Вышеописанный пример кому-то может показаться странным, ведь получается, что мы усложнили код класса ради сомнительного выигрыша в коде обращения. На самом деле, в реальных условиях, с настоящими классами, с большим количеством свойств и в сложных выражениях, выигрыш становится куда более заметен. Сравните два примера одного и того же участка кода, один из которых написан на C++, другой на K++. Несмотря на то, что приведенный код тоже взят &amp;quot;с потолка&amp;quot;, разница в читаемости уже более заметна. В целом, чем сложнее выражение и чем больше в нем применяется операций присваивания и доступа к полям классов — тем большее преимущество дает использование свойств:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
Object1.SetStatus(Object2.GetStatus() &amp;gt; 0 ? Object2.GetStatus() : DefaultObject.GetStatus());&lt;br /&gt;
printf(&amp;quot;object %s (%d) located at %s : status changed to %u&amp;quot;, &lt;br /&gt;
    Object1.GetName(), Object1.GetIndex(), Object1.GetLocation(), Object1.GetStatus());&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
Object1.status = Object2.status &amp;gt; 0 ? Object2.status : DefaultObject.status;&lt;br /&gt;
println(&amp;quot;object % (%) located at % : status changed to %&amp;quot;, &lt;br /&gt;
    Object1.name, Object1.index, Object1.location, Object1.status);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В качестве второго примера мы приведем код, более близкий к реальной жизни. Как известно, многие элементы управления современных графических интерфейсов могут находится в состоянии &amp;quot;активен&amp;quot; или &amp;quot;не активен&amp;quot;. Неактивные элементы не реагируют на действия пользователя (например, кнопки не будут нажиматься) и как правило окрашиваются в оттенки серого (для того чтобы нельзя было их спутать с активными элементами). Естественно, это поведение определяется некоторым полем в объекте элемента управления. В зависимости от его значения, библиотека графического интерфейса будет по разному обрабатывать и отрисовывать этот элемент управления.&lt;br /&gt;
&lt;br /&gt;
В языке К++ это поведение можно легко описать, используя двусторонние свойства, то есть такие, которые можно использовать как на чтение так и на запись. Логично предположить, что чтение такого свойства не должно сказываться на самом элементе управления, в то время как запись в свойство должна дать команду элементу управления изменить свое состояние и соответственно внешний вид. Вот пример описания некоторого абстрактного класса элемента управления:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
class Widget {&lt;br /&gt;
    var m_Enabled = true; //поле, хранящее текущее состояние активности&lt;br /&gt;
    function void SetEnabled(const value) {&lt;br /&gt;
        var old_value = m_Enabled;&lt;br /&gt;
        m_Enabled = value;&lt;br /&gt;
        if (old_value != m_Enabled)&lt;br /&gt;
            Invalidate(); //Состояние изменилось, обновляем элемент управления&lt;br /&gt;
    }&lt;br /&gt;
    property enabled read m_Enabled write SetEnabled;&lt;br /&gt;
    //далее идет остальная часть класса, например методы отрисовки&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь, если мы унаследуем некоторый класс от данного класса и переопределим соответствующие методы отрисовки, то у класса потомка так же можно будет использовать свойство &amp;lt;tt&amp;gt;enabled&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var myForm = new Form; //создаем окно&lt;br /&gt;
var myButton = Button.CreateAtPos(myForm, 10, 10); //добавляем кнопку&lt;br /&gt;
myButton.caption = &amp;quot;Click me!&amp;quot;; //устанавливаем подпись&lt;br /&gt;
myButton.OnClick += { |x| x.enabled = false; }; //подключаем обработчик события&lt;br /&gt;
myForm.Show(); //показываем окно&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Приведенный выше код создаст окно и разместит на нем кнопку (подразумевается, что класс &amp;lt;tt&amp;gt;Button&amp;lt;/tt&amp;gt; унаследован от нашего класса &amp;lt;tt&amp;gt;Widget&amp;lt;/tt&amp;gt;). Затем устанавливаются свойства кнопки, такие как подпись и [[Блоки|блок]] обработчика события &amp;lt;tt&amp;gt;OnClick&amp;lt;/tt&amp;gt;. При нажатии на кнопку она станет неактивной.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
В заключение, кратко опишем синтаксис объявления свойства и поясним его. Итак, объявление любого свойства начинается с указания ключевого слова &amp;lt;tt&amp;gt;'''property'''&amp;lt;/tt&amp;gt;, после которого идет [[идентификатор]] типа свойства. Тип может быть опущен, тогда для свойства будет определен [[Переменные#Нетипированные (динамические) переменные|динамический тип]]. Затем указывается идентификатор имени свойства. &lt;br /&gt;
&lt;br /&gt;
Оставшаяся часть зависит от того, какое свойство объявляется:&lt;br /&gt;
&lt;br /&gt;
* Если объявляется свойство на чтение, то указывается ключевое слово &amp;lt;tt&amp;gt;'''read'''&amp;lt;/tt&amp;gt;, после которого идет либо идентификатор имени поля, которое нужно читать, либо имя метода, который должен использоваться как ''аксессор''. В роли аксессора может выступать метод, не принимающий параметров и возвращающий некоторое значение, которое будет возвращаться как значение свойства.&lt;br /&gt;
* Если объявляется свойство на запись, то указывается, соответственно ключевое слово &amp;lt;tt&amp;gt;'''write'''&amp;lt;/tt&amp;gt; после которого идет либо имя поля, которое нужно записывать, либо имя метода, который должен использоваться как ''мутатор''. В качестве мутатора может выступать метод, принимающий один параметр. Возвращаемое значение игнорируется, так что оно может быть любым.&lt;br /&gt;
* Если объявляется свойство, доступное как на чтение так и на запись, то указываются обе части, причем первой идет часть чтения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' Если тип свойства указан явно, то в зависимости от типа поля либо типа возвращаемого значения аксессора, может быть выполнена операция [[Приведение типов|приведения типов]]. Разумеется, если тип поля или результат аксессора неприводим к указанному типу свойства, то будет выдано сообщение об ошибке. Аналогичная ситуация обстоит и с параметром мутатора.&lt;br /&gt;
&lt;br /&gt;
Кратко, синтаксис объявления свойства можно описать в стиле справки к командам оболочки:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
property [тип] &amp;lt;имя&amp;gt; [read &amp;lt;аксессор|поле&amp;gt;] [write &amp;lt;мутатор|поле&amp;gt;];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Расширения ==&lt;br /&gt;
&lt;br /&gt;
Иногда бывает необходимо расширить функциональность некоторого существующего класса без порождения дочернего класса. Это может быть необходимо в тех случаях, когда исходный класс уже используется в коде программы и порождение нового класса нарушило бы спецификацию на интерфейс, либо потребовало значительных изменений в исходных текстах программы. В таких случаях целесообразно применять т. н. ''расширения классов''. Синтаксически, конструкция расширения практически не отличается от конструкции объявления класса, однако методы и свойства перечисленные в нем, дополняются к исходному классу, то есть наследования не происходит.&lt;br /&gt;
&lt;br /&gt;
Как правило, расширения применяются к классам [[Стандартной библиотека Gide|стандартной библиотеки]], либо к [[unmanaged код|неуправляемым классам]].&lt;br /&gt;
&lt;br /&gt;
В качестве примера приведем код, расширяющий функциональность класса &amp;lt;tt&amp;gt;[[Стандартные типы данных#Целые числа|int]]&amp;lt;/tt&amp;gt; с помощью свойства &amp;lt;tt&amp;gt;factorial&amp;lt;/tt&amp;gt;. Расширения объявляются путем указания ключевого слова &amp;lt;tt&amp;gt;'''extend'''&amp;lt;/tt&amp;gt;, после которого указывается [[идентификатор]] имени класса, который следует расширить. Затем идет тело расширения, такое же как при описании классов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
package intmod_fact;&lt;br /&gt;
import std;&lt;br /&gt;
external console_stream STDOUT;&lt;br /&gt;
function void println(const string s) { STDOUT.print(s + &amp;quot;\n&amp;quot;); }&lt;br /&gt;
&lt;br /&gt;
extend int {&lt;br /&gt;
    const function ubigint GetFactorial() {&lt;br /&gt;
        var ubigint result = 1, int x;&lt;br /&gt;
        for (x = this; x &amp;gt; 1; --x)&lt;br /&gt;
            result *= x;&lt;br /&gt;
        return result;&lt;br /&gt;
    }&lt;br /&gt;
    property ubigint factorial read GetFactorial;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
export function main() {&lt;br /&gt;
    println(&amp;quot;Factorial of 10 is &amp;quot; + 10.factorial);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;6-14: Мы объявляем расширение класса &amp;lt;tt&amp;gt;[[Стандартные типы данных#Целые числа|int]]&amp;lt;/tt&amp;gt;, реализованного в [[Стандартная библиотека gide|стандартной библиотеке]]. Добавляется частный метод &amp;lt;tt&amp;gt;GetFactorial()&amp;lt;/tt&amp;gt;, и свойство &amp;lt;tt&amp;gt;factorial&amp;lt;/tt&amp;gt;, связанное с методом. Как видно из названия, метод рассчитывает факториал числа, которое содержится в объекте. В данном контексте, специальная переменная ''this'' имеет тип &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt; и ссылается на сам объект. Таким образом, для числа 10 переменная ''this'' будет равна 10.&lt;br /&gt;
&lt;br /&gt;
;17: Здесь мы видим применение расширения в действии. Константа 10 на момент компиляции преобразуется в [[Константы#Константные объекты|константный объект]] класса &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;, который подобно любому другому объекту этого же класса будет иметь свойство &amp;lt;tt&amp;gt;factorial&amp;lt;/tt&amp;gt;, которое мы и используем. При попытке чтения из этого свойства будет вызван метод &amp;lt;tt&amp;gt;GetFactorial()&amp;lt;/tt&amp;gt;, результат выполнения которого возвращается как значение свойства, то есть как факториал числа. &amp;lt;!--Его мы вызываем с помощью специального синтаксиса, для передачи блока в качестве [[Функции#Аргументы|параметра функции]]. При этом, сам блок указывается прямо в коде вызова функции. Тело блока состоит из одного вызова функции, выводящей текущее число в стандартный поток вывода. --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
: Обратите внимание, что функция &amp;lt;tt&amp;gt;println()&amp;lt;/tt&amp;gt;, принимает в качестве параметра [[Стандартные типы данных#Строки|строку]], в то время как тип свойства определен как &amp;lt;tt&amp;gt;[[Стандартные типы данных#Целые числа|ubigint]]&amp;lt;/tt&amp;gt;. В этом нет ничего странного, потому что класс &amp;lt;tt&amp;gt;ubigint&amp;lt;/tt&amp;gt; имеет [[Типы операторов#Операторы приведения типов|оператор приведения типа]] к классу &amp;lt;tt&amp;gt;[[Стандартные типы данных#Строки|string]]&amp;lt;/tt&amp;gt;, который вызывается компилятором автоматически. Таким образом, при вычислении значения выражения в скобках, сперва значение факториала ''приводится'' к типу строки, которая складываясь со строкой слева от оператора &amp;lt;tt&amp;gt;+&amp;lt;/tt&amp;gt; передается в качестве параметра функции.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' При работе с расширениями существует одно важное ограничение. Расширять классы можно только методами и свойствами, но не полями. Это связано с внутренней организацией языка К++ и виртуальной машины. Дополнительно стоит отметить, что методы объявленные в расширении будут перекрывать соответствующие им методы класса (имеется в виду ситуация когда имена и наборы параметров полностью совпадают). Важно понимать, что такое перекрытие не является объявлением виртуального метода — происходит именно замещение старого метода новым. &lt;br /&gt;
&lt;br /&gt;
== Смотри также ==&lt;/div&gt;</summary>
		<author><name>KroTozeR</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%9A%D0%BE%D0%BD%D1%81%D1%82%D0%B0%D0%BD%D1%82%D1%8B</id>
		<title>Константы</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%9A%D0%BE%D0%BD%D1%81%D1%82%D0%B0%D0%BD%D1%82%D1%8B"/>
				<updated>2007-10-01T09:16:38Z</updated>
		
		<summary type="html">&lt;p&gt;KroTozeR: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Понятие константы ==&lt;br /&gt;
&lt;br /&gt;
В сущности, и с точки зрения языка, ''константы'' это те же [[переменные]], за исключением того, что однажды установленное их значение нельзя изменять. В остальном они ведут себя так же как обычные [[объекты]]: их можно использовать в арифметических выражениях, передавать в качестве [[Функции#Аргументы|параметров]] [[Функции|функциям]], использовать их [[K++ как объектно-ориентированный язык#Свойства|свойства]] и вызывать [[K++ как объектно-ориентированный язык#Методы|методы]]. Разумеется, только те, которые не изменяют состояние самого объекта.&lt;br /&gt;
&lt;br /&gt;
Объявление любой константы начинается с ключевого слова &amp;lt;tt&amp;gt;'''const'''&amp;lt;/tt&amp;gt;, за которым идут тип (можно не указывать),  [[идентификатор]] имени константы и выражение-инициализатор. &lt;br /&gt;
&lt;br /&gt;
Вот примеры объявления констант:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt; &lt;br /&gt;
const real e = 2.7182818;&lt;br /&gt;
const pi = 3.1415926;&lt;br /&gt;
const s = &amp;quot;hello world&amp;quot;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тип константы можно либо указать явно, как это происходит в случае константы ''e'', либо неявно. При этом он будет назначен как тип инициализатора: константа ''pi'' будет иметь тип числа с плавающей точкой (&amp;lt;tt&amp;gt;[[Стандартные типы данных#Числа с плавающей точкой|real]]&amp;lt;/tt&amp;gt;), а константа ''s'' — строковый тип (&amp;lt;tt&amp;gt;[[Стандартные типы данных#Строки|string]]&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' При объявлении констант следите за тем, чтобы их тип был ясно виден из строки объявления. Если выражение инициализатора представляет собой довольно сложное математическое выражение, либо содержит вызовы функций, лучше всего указать тип константы явно (как в примере с константой ''e''). Иначе, это может вызывать проблемы в будущем, при работе программы или при ее отладке. В целом ситуация такая же, что и с инициализацией переменных ([[Переменные#Типизация при инициализации|см. примечание]]).&lt;br /&gt;
&lt;br /&gt;
== Константные объекты ==&lt;br /&gt;
&lt;br /&gt;
Как уже было сказано выше, константами могут являться или быть объявлены любые объекты языка. Даже числа и строки, фигурирующие в программе в явном виде — тоже являются константными объектами. И их тоже можно использовать как объекты. &lt;br /&gt;
&lt;br /&gt;
Например, так можно узнать длину строки, используя свойство &amp;lt;tt&amp;gt;length&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;var len = &amp;quot;hello world&amp;quot;.length();&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В общем случае, создать константный объект можно тем же способом что и обычную переменную-экземпляр класса:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
const myinstance = new MyClass;&lt;br /&gt;
const myobject = MyClass.Create();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Константные функции ==&lt;br /&gt;
&lt;br /&gt;
При работе с константными объектами подразумевается, что их значение (простые объекты, вроде числовой константы) или в общем случае их состояние (экземпляр некоторого класса) не будут изменено. Чтобы указать компилятору, какие методы и операторы можно использовать, а какие нет, вводится понятие ''спецификатора функции''. Спецификатор &amp;lt;tt&amp;gt;'''const'''&amp;lt;/tt&amp;gt;, указанный в объявлении метода или оператора указывает на то, что этот метод не изменяет состояния объекта и может вызываться для констант:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
class MyClass {&lt;br /&gt;
    var m_i = 0;&lt;br /&gt;
    public const function ShowStatus() { println(m_i); } &lt;br /&gt;
    public function Check() { return i &amp;gt; 5; }&lt;br /&gt;
    function SetI(value) { m_i = value; }&lt;br /&gt;
    property i read m_i write SetI;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В том случае, если где-то в коде будет создан константный экземпляр класса, то он будет допускать чтение свойства ''i'' и вызовы метода &amp;lt;tt&amp;gt;ShowStatus()&amp;lt;/tt&amp;gt;, но не &amp;lt;tt&amp;gt;SetI()&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var v = new MyClass;   //создаем экземпляр-переменную&lt;br /&gt;
const c = new MyClass; //создаем экземпляр-константу&lt;br /&gt;
&lt;br /&gt;
println('v =' + v.i);  //можно, доступ на чтение&lt;br /&gt;
println('c =' + c.i);  //тоже можно, чтение свойства разрешено&lt;br /&gt;
v.i = 5;               //можно, v - переменная&lt;br /&gt;
c.i = v.i;             //нельзя, c - константа, запись свойства запрещена&lt;br /&gt;
v.Check();             //можно&lt;br /&gt;
&lt;br /&gt;
c.Check();             //нельзя. метод не помечен как const &lt;br /&gt;
                       //(хоть и не изменяет состояния)&lt;br /&gt;
&lt;br /&gt;
v.ShowStatus();        //можно&lt;br /&gt;
c.ShowStatus();        //тоже можно, метод не меняет состояния (помечен как const)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>KroTozeR</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%9F%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D1%8B%D0%B5</id>
		<title>Переменные</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%9F%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D1%8B%D0%B5"/>
				<updated>2007-10-01T09:09:31Z</updated>
		
		<summary type="html">&lt;p&gt;KroTozeR: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
== Понятие переменной, тип переменной ==&lt;br /&gt;
&lt;br /&gt;
В классических книгах по программированию, под переменными понимают некоторую поименованную область памяти, либо регистр процессора. В нашем же случае, мы имеем дело с виртуальной машиной, соответственно ни регистров, ни памяти в обычном понимании у нас нет. Все, с чем мы имеем дело, это с объектами в &amp;quot;сознании&amp;quot; виртуальной машины. Так или иначе, но и там и тут переменные служат для одной цели: для хранения некоторой информации. Ей могут быть и исходные данные программы, и некоторые промежуточные значения, или же результаты выполнения программы. Впрочем, некоторые программы могут не иметь исходных данных (например, генератор текстур), другие же могут не производить никакого вывода, так что все это довольно условно.&lt;br /&gt;
&lt;br /&gt;
Поэтому, будем считать проще, что переменная это просто некоторая сущность, некоторый объект, способный хранить данные. Под данными мы будем понимать любую информацию, которую возможно представить в цифровом виде.&lt;br /&gt;
&lt;br /&gt;
=== Тип переменной ===&lt;br /&gt;
&lt;br /&gt;
Часто с понятием переменной связывают понятие ее типа. Стоит отметить, что это понятие так же является математической абстракцией. С точки зрения самой машины все данные представляют собой одно и то же — совокупность нулей и единиц. А что под ними понимать в каждом конкретном случае — решает уже программист. Так вот, в некотором смысле ''тип переменной'' показывает, что именно хранится в данной переменной. &lt;br /&gt;
&lt;br /&gt;
Наиболее распространенные типы переменных это:&lt;br /&gt;
* Логический тип, принимающий только два значения (&amp;quot;истина&amp;quot; и &amp;quot;ложь&amp;quot;)&lt;br /&gt;
* Целые числа различной длины (байт, слово, двойное слово и т. д.)&lt;br /&gt;
* Числа с плавающей точкой&lt;br /&gt;
* Строки (последовательность байтов в памяти, воспринимаемая как строка текста)&lt;br /&gt;
* Указатели (переменные, содержащие в себе адрес другой переменной)&lt;br /&gt;
* Составные типы (некоторая совокупность из вышеперечисленных типов)&lt;br /&gt;
&lt;br /&gt;
Как уже говорилось выше, первоначально о типе переменной знал только программист, пишущий программу.  Естественно, вся ответственность за соблюдение соответствия типов выполняемым операциям была возложена на самого программиста. Постепенно, с развитием языков программирования высокого уровня, была выдвинута идея явным образом сопоставлять переменной ее тип. Это обеспечивало большее удобство в написании программ, поскольку всю работу по контролю над типами выполнял сам компилятор, который выдавал сообщения об ошибках, если типы переменных не соответствовали операциям, или была вероятность неверного их истолкования. Так появились языки со статической типизацией.&lt;br /&gt;
&lt;br /&gt;
== Статическая типизация на примере C++ ==&lt;br /&gt;
&lt;br /&gt;
Итак, ''статическая типизация'' это — приём, при котором переменная, параметр подпрограммы или возвращаемое значение функции связывается с типом в момент объявления и этот тип не может быть изменён позже (переменная или параметр будут принимать, а функция будет возвращать значения только этого типа). &lt;br /&gt;
&lt;br /&gt;
То есть, если мы объявляем переменные целочисленного типа как &amp;lt;tt&amp;gt;int i, j;&amp;lt;/tt&amp;gt; то мы можем выполнять над ними только операции, соответствующие понятиям этого типа, вроде операции сложения &amp;lt;tt&amp;gt;i + j&amp;lt;/tt&amp;gt; или операции присваивания одной переменной другой &amp;lt;tt&amp;gt;i = j&amp;lt;/tt&amp;gt;. Если же мы попытаемся присвоить такой переменной значение другого, ''неприводимого'' типа, например &amp;lt;tt&amp;gt;i = &amp;quot;hello world&amp;quot;&amp;lt;/tt&amp;gt; то компилятор выдаст ошибку.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим кратко преимущества и недостатки статически типированных языков и сравним их впоследствии с другими подходами к типизации.&lt;br /&gt;
&lt;br /&gt;
Преимущества статической типизации:&lt;br /&gt;
* Строгость программ&lt;br /&gt;
* Большая возможность оптимизации, а, следовательно:&lt;br /&gt;
** Высокая скорость работы&lt;br /&gt;
** Минимальные требования к памяти&lt;br /&gt;
&lt;br /&gt;
Недостатки:&lt;br /&gt;
* Необходимость объявления типов даже там где это очевидно&lt;br /&gt;
* Засорение кода программы дополнительными символами, а, следовательно:&lt;br /&gt;
** Отвлечение внимания программиста от самой задачи в сторону рутины формализации&lt;br /&gt;
** Плохая читаемость кода&lt;br /&gt;
* Необходимость дополнительных ухищрений для передачи параметров разных типов&lt;br /&gt;
* Невозможность написания абстрактных алгоритмов&lt;br /&gt;
&lt;br /&gt;
'''Вывод:''' Программы, написанные на языках со статической типизацией, обладают большой эффективностью и производительностью, однако это дается ценой строгости и определенности. Программирование на таких языках это принятие их правил игры, при этом программист должен мыслить в жестко ограниченных рамках. Вот почему эти языки чаще всего применяются именно для системного программирования, где в первую очередь важна производительность полученного кода, и только потом удобство его написания и поддержки.&lt;br /&gt;
&lt;br /&gt;
== Динамическая типизация на примере Ruby ==&lt;br /&gt;
&lt;br /&gt;
Впоследствии, в противовес статической типизации была разработана модель динамически типированных языков. При таком подходе, переменная не имеет заранее определенного типа, а принимает тип при инициализации и при присвоении ей некоторого значения. Таким образом, в различных участках программы одна и та же переменная может принимать значения разных типов. &lt;br /&gt;
&lt;br /&gt;
На первый взгляд это может показать странным, особенно с точки зрения программиста, привыкшего к статически типированным языкам (таким как С++ или Паскаль). На самом деле здесь нет ничего страшного или нелогичного. Все мы в своей жизни, сами того не подозревая, оперируем понятиями динамических переменных. Один и тот же объект в разных ситуациях мы можем воспринимать с разных точек зрения. Задавая вопрос &amp;quot;как пройти в библиотеку&amp;quot;, мы можем получить как конкретный ответ &amp;quot;в 3 часа ночи?! идиот!&amp;quot; так и целый набор: &amp;quot;на автобусе номер 23, на такси или пешком, тут не очень далеко&amp;quot;. При этом нас совершенно не смущает то, что мы заранее не знаем, каков будет результат, наоборот — это дает нам большую гибкость и свободу действий; мы двигаемся дальше на основании того, каков был результат предыдущей операции. Подобно этому примеру, мы можем писать программы, которые оперируют переменными неопределенного типа. В результате, код получается более лаконичным, более читаемым и, в конце концов, более близким к естественному восприятию человека (ведь именно этого мы ждем от языков программирования!).&lt;br /&gt;
&lt;br /&gt;
Концепция динамической типизации в полной мере нашла свое применение в языке Ruby. В этом языке любая переменная может в разное время иметь различные типы. Вот пример кода на этом языке:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def get_data(need_array = false)&lt;br /&gt;
  result = 0     # целое число&lt;br /&gt;
  if need_array&lt;br /&gt;
    result = [ 1, 2, 3, 4 ]  # тип меняется на Array&lt;br /&gt;
  else&lt;br /&gt;
    result = { 1 =&amp;gt; 2, 3 =&amp;gt; 4}  # тип меняется на Hash&lt;br /&gt;
  end&lt;br /&gt;
  result&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Преимущества динамической типизации:&lt;br /&gt;
* Легкость написания программ&lt;br /&gt;
* Лаконичность и хорошая читаемость&lt;br /&gt;
* Высокая гибкость языка. Возможность решения проблемы разными способами&lt;br /&gt;
* Большая возможность повторного использования кода (абстрактные алгоритмы)&lt;br /&gt;
&lt;br /&gt;
Недостатки:&lt;br /&gt;
* Существенно меньшая производительность, по сравнению со статически типированными языками&lt;br /&gt;
* Сложность в написании оптимизаторов, их малая эффективность&lt;br /&gt;
* Как правило, динамически типированные языки являются интерпретаторами (компиляция неэффективна)&lt;br /&gt;
&lt;br /&gt;
'''Вывод:''' Языки с динамической типизацией очень удобны для использования на прикладном уровне. Учитывая их высокую гибкость и лаконичность, программисту легче излагать свои мысли, при том, что свое внимание он концентрирует на самой задаче, не отвлекаясь на частные проблемы реализации. Конечно, они уступают по эффективности статическим, компилируемым языкам, однако это уже вопрос, требующий отдельного рассмотрения в рамках конкретно поставленной задачи.&lt;br /&gt;
&lt;br /&gt;
== Полудинамическая типизация ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрев преимущества и недостатки статической и динамической типизации, мы подходим к мысли объединения этих двух подходов в рамках одного языка. Языка, который бы сочетал в себе все преимущества динамической типизации, с возможностью указания типов там, где это необходимо. В результате мы получили бы язык, достаточно гибкий и в то же время позволяющий эффективно работать с типами.&lt;br /&gt;
&lt;br /&gt;
Язык К++ как раз и ставит перед собой задачу совмещения этих двух подходов. Переменные этого языка могут быть либо типированными, либо не типированными (динамическими). Первые обеспечивают производительность, вторые — гибкость. Достигается это, прежде всего ценой того, что переменная не может изменять свой тип во время выполнения программы. Однако это относится только к статически типированным переменным. Полностью динамические переменные этого недостатка лишены. &lt;br /&gt;
&lt;br /&gt;
При разработке программы на языке К++, программист должен стараться держать баланс между удобством написания программы и ее эффективностью. В целом, рекомендуется указывать типы переменных везде, где это возможно. Динамические же переменные следует применять в тех местах, где заранее неизвестно, с каким типом переменной придется работать. При этом код получится достаточно производительным и одновременно гибким.&lt;br /&gt;
&lt;br /&gt;
== Типизация при объявлении ==&lt;br /&gt;
&lt;br /&gt;
Язык К++ позволяет задавать тип переменной несколькими способами. Одним из них является типирование переменной при объявлении. При этом необходимо написать ключевое слово &amp;lt;tt&amp;gt;'''var'''&amp;lt;/tt&amp;gt;, за которым следует [[идентификатор]] типа переменной, а затем ее имя. Точка с запятой (;) завершает конструкцию:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var int i;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь мы объявили [[Стандартные типы данных#Числа|целочисленную]] переменную с именем ''i'' и неявно [[Инициализация|инициализировали]] ее значением 0. Такой синтаксис удобен в тех случаях, когда заранее неизвестно каким должно быть значение переменной. Видимо, в данном случае программист решил, что оно будет присвоено явным образом впоследствии. Если же заранее ясно, что на момент объявления переменная должна иметь определенное значение, следует применять синтаксис ''объявления с инициализацией''.&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' Неявная инициализация это причина многих трудноуловимых ошибок времени выполнения. В языке К++ это имеет менее разрушительные последствия, чем например в С++ (где значение неинициализированной переменной может быть абсолютно произвольным!), тем не менее '''настоятельно рекомендуется инициализировать переменные''' сразу при объявлении. Это избавит вас от опасности забыть присвоить значение переменной впоследствии.&lt;br /&gt;
&lt;br /&gt;
== Типизация при инициализации ==&lt;br /&gt;
&lt;br /&gt;
Более предпочтительным способом объявления типированной переменной является ''объявление с инициализацией''. В данном случае, под ''инициализацией'' понимается процесс начального задания значения переменной. Для этого следует так же написать ключевое слово &amp;lt;tt&amp;gt;'''var'''&amp;lt;/tt&amp;gt;, после которого сразу идет [[идентификатор]] имени переменной, а затем выражение — инициализатор, присваивающее значение вновь созданной переменной. При этом тип переменной будет определен как тип инициализатора:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var i = 0;&lt;br /&gt;
var s = &amp;quot;hello world&amp;quot;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В приведенном выше примере, переменной ''i'' будет назначен целочисленный тип (&amp;lt;tt&amp;gt;[[Стандартные типы данных#Целые числа|int]]&amp;lt;/tt&amp;gt;), в то время как переменная ''s'' будет иметь строковый тип (&amp;lt;tt&amp;gt;[[Стандартные типы данных#Строки|string]]&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' В некоторых случаях может сложиться ситуация, что инициализатор переменной это довольно сложное выражение. При этом программисту сложно определить, какой же на самом деле будет тип переменной. Для ясности приведем пример из разряда &amp;quot;как не надо делать&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var x = 2+3*4+f(3)/3*0.2;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Синтаксически здесь все верно. Переменная будет создана и ей будет назначен некоторый тип. Но вот какой? Опытный читатель заметит, что в выражении присутствуют константы с плавающей точкой и операция деления. Стало быть, в результате [[Приведение типов|приведения типов]], результирующий тип переменной так же будет [[Стандартные типы данных#Числа с плавающей точкой|числом с плавающей точкой]]. Внимательный же читатель заметит так же, что в выражении присутствует [[Выражения#Вызов функций|вызов функции]] &amp;lt;tt&amp;gt;f(3)&amp;lt;/tt&amp;gt;. И тут дело обстоит еще хуже. [[Функции|Функция]] может возвращать значение любого типа. Чтобы узнать какого именно, нужно обратиться к документации, либо к описанию самой функции. А что если она возвращает нетипированную переменную ([[Переменные#Нетипированные (динамические) переменные|см. ниже]])? Тогда предсказать тип переменной будет еще сложнее (если забежать вперед, то можно сказать что результат выражения так же будет нетипирован).&lt;br /&gt;
&lt;br /&gt;
Скорее всего, Читатель уже согласился с мыслью, что подобных конструкций следует избегать. Однако что же делать, если все же требуется завести переменную, которая должна быть инициализирована подобным образом? Выхода тут может быть два. Либо отделить объявление переменной от ее инициализации, либо совместить типированное объявление с инициализацией.&lt;br /&gt;
&lt;br /&gt;
Первый вариант:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var real x;&lt;br /&gt;
... //где то по коду программы&lt;br /&gt;
x = 2+3*4+f(3)/3*0.2; &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Второй, более удачный вариант:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var real x = 2+3*4+f(3)/3*0.2;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Стоит отметить, что во втором случае будет выполнена операция [[Приведение типов|приведения типов]], то есть будет сделана попытка преобразовать тип значения инициализатора к явно указанному типу переменной. Если тип инициализатора возможно ''привести'' к типу переменной, то все пройдет успешно. Если же типы ''неприводимы'', то произойдет либо ошибка компиляции (при статическом типе инициализатора), либо ошибка времени выполнения.&lt;br /&gt;
&lt;br /&gt;
== Нетипированные (динамические) переменные ==&lt;br /&gt;
&lt;br /&gt;
Иногда бывает необходимо работать с переменной, тип которой на момент компиляции неизвестен. В этом случае применяются ''нетипированные'' или ''динамические'' переменные. Такие переменные объявляются просто, путем написания ключевого слова &amp;lt;tt&amp;gt;'''var'''&amp;lt;/tt&amp;gt;, за которым идет [[идентификатор]] имени переменной:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var x;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ходе работы программы, такая переменная может принимать значения любых типов. Она будет автоматически приводиться к нужным типам (и наоборот), что, в конечном счете, обеспечивает гибкость кода.&lt;br /&gt;
&lt;br /&gt;
Примером применения динамических переменных могут послужить контейнеры — объекты, которые могут хранить в себе другие объекты. Простейшими примерами контейнеров могут послужить [[Стандартные типы данных#Массивы|массивы]]. В языке К++ массивы не являются типированными. Они могут хранить любые объекты, даже объекты различных типов. Разумеется, сам массив оперирует со своими элементами как с нетипированными переменными (ведь он не знает заранее, объекты каких типов будут в него класть). &lt;br /&gt;
&lt;br /&gt;
Программист может написать некоторую подпрограмму для обработки элементов массива, например для их сортировки. При этом все, что ему нужно знать это способ перебора элементов контейнера и некоторую операцию сравнения двух элементов, для выяснения их очередности (эту операцию контейнеру предоставляет пользователь; как именно это делается, будет описано [[Блоки#Применение блоков|дальше]]). Этим достигается эффективность написания кода, и открываются широкие возможности по повторному использованию кода. К примеру, в традиционных типированных языках вроде Паскаля, пришлось бы реализовывать отдельные методы сортировки строк, числовых массивов и т. д., здесь же мы обходимся одной реализацией.&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' Применение динамических переменных негативно сказывается на эффективности работы программы и на скорости ее выполнения. Поэтому старайтесь применять динамические переменные только там где это действительно необходимо, либо там где не требуется высокая производительность.&lt;br /&gt;
&lt;br /&gt;
== О важности инициализации переменных ==&lt;br /&gt;
&lt;br /&gt;
В заключение этой главы, приведем краткое обобщение материала относительно инициализации переменных. Как уже было сказано выше, инициализация переменных это важный момент, правильное понимание которого позволит программисту писать более эффективные программы, и в то же время избавить себя от многих типичных ошибок программирования. В ходе изучения языка постарайтесь выработать у себя некоторые шаблоны проектирования, следуя которым вы избавите себя от возможных проблем.&lt;br /&gt;
&lt;br /&gt;
Вот некоторый список рекомендаций относительно объявления переменных:&lt;br /&gt;
* Старайтесь всегда объявлять переменные, инициализируя их&lt;br /&gt;
* Если выражение инициализатора достаточно сложное, либо содержит вызовы функций, применяйте явное типирование объявляемой переменной, либо используйте [[приведение типов]] в самом выражении&lt;br /&gt;
* Объявляйте переменные как можно ближе к месту их использования&lt;br /&gt;
* Нетипированные переменные применяйте только в тех случаях, где это действительно необходимо&lt;br /&gt;
&lt;br /&gt;
Конечно, этот список далеко не полный, да он и не претендует на полноту. То, что написано выше ни в коем случае не является правилом, которому нужно следовать непременно, везде и всегда. Границы разумного определяете вы сами. Просто старайтесь не упускать этих моментов из виду.&lt;/div&gt;</summary>
		<author><name>KroTozeR</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5,_%D0%B8%D0%BB%D0%B8_%D0%BA%D1%80%D0%B0%D1%82%D0%BA%D0%B8%D0%B9_%D0%BE%D0%B1%D0%B7%D0%BE%D1%80</id>
		<title>Введение, или краткий обзор</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5,_%D0%B8%D0%BB%D0%B8_%D0%BA%D1%80%D0%B0%D1%82%D0%BA%D0%B8%D0%B9_%D0%BE%D0%B1%D0%B7%D0%BE%D1%80"/>
				<updated>2007-10-01T08:47:51Z</updated>
		
		<summary type="html">&lt;p&gt;KroTozeR: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
(Введение...)&lt;br /&gt;
&lt;br /&gt;
== Здравствуй, мир! ==&lt;br /&gt;
&lt;br /&gt;
Классический пример программы, выводящей строку &amp;quot;Hello, world!&amp;quot; на экран, на языке K++ выглядит следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
package hello_world;&lt;br /&gt;
&lt;br /&gt;
external console_stream STDOUT;&lt;br /&gt;
&lt;br /&gt;
export function void main()&lt;br /&gt;
{&lt;br /&gt;
    STDOUT.print(&amp;quot;Hello, world!\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;1: Как уже [[Модули|отмечалось ранее]], в K++ любая программа или библиотека является модулем. Ключевое слово &amp;lt;tt&amp;gt;'''package'''&amp;lt;/tt&amp;gt; используется для объявления имени модуля, в который должна быть скомпилирована программа.&lt;br /&gt;
&lt;br /&gt;
;3: Здесь мы объявляем глобальную переменную ''STDOUT'', имеющую тип &amp;lt;tt&amp;gt;console_stream&amp;lt;/tt&amp;gt;. Ключевое слово &amp;lt;tt&amp;gt;'''external'''&amp;lt;/tt&amp;gt; помечает переменную как ''внешнюю'' — т.е. создаваемую пользователем. &lt;br /&gt;
&lt;br /&gt;
;5-8: Наконец, объявляется функция &amp;lt;tt&amp;gt;main()&amp;lt;/tt&amp;gt;, которая вызывает метод &amp;lt;tt&amp;gt;print()&amp;lt;/tt&amp;gt; объекта ''STDOUT'', передав ему строку &amp;quot;Hello, world!\n&amp;quot; в качестве параметра.&lt;br /&gt;
&lt;br /&gt;
: Ключевое слово &amp;lt;tt&amp;gt;'''export'''&amp;lt;/tt&amp;gt; говорит о том, что имя функции не следует декорировать. Декорирование имен применяется для того, чтобы дать возможность [[Функции#Перегрузка функций и операторов|перегружать функции]] с одинаковыми именами, но разными списками параметров (или параметрами разных типов).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Теперь несколько слов о том, как такая программа будет запущена. В первую очередь стоит отметить, что нет никаких стандартов на имя функции &amp;lt;tt&amp;gt;main()&amp;lt;/tt&amp;gt; или объекта ''STDOUT''. На платформе Gide каждая программа является библиотекой, и порядок ее использования полностью определяется пользователем. В данном случае предполагается, что программа будет запускаться при помощи консольной команды '''gide.run''', реализованной в модуле стандартной библиотеки. Эта команда определяет три глобальные переменные ''STDIN'', ''STDOUT'' и ''STDERR'', имеющие тип &amp;lt;tt&amp;gt;console_stream&amp;lt;/tt&amp;gt; и запускает функцию &amp;lt;tt&amp;gt;main()&amp;lt;/tt&amp;gt;, экспортируемую программой.&lt;br /&gt;
&lt;br /&gt;
Если бы мы, скажем, писали программу, генерирующую текстуру — никакой функции &amp;lt;tt&amp;gt;main()&amp;lt;/tt&amp;gt; в ней не было бы. Набор экспортируемых ей функций полностью определялся бы требованиями генератора текстур, которые описаны в соответствующей документации.&lt;br /&gt;
&lt;br /&gt;
== Более сложный пример ==&lt;br /&gt;
&lt;br /&gt;
Вот более сложный пример, демонстрирующий использование переменных и циклов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
package sums;&lt;br /&gt;
&lt;br /&gt;
export function void main()&lt;br /&gt;
{&lt;br /&gt;
    var ary = [ 1, 2, 3, 4 ];&lt;br /&gt;
    var sums = new array;&lt;br /&gt;
    var int i;&lt;br /&gt;
    sums.push(ary[0]);&lt;br /&gt;
    for(i = 1; i &amp;lt; ary.size(); ++i)&lt;br /&gt;
        sums.push(sums[i-1] + ary[i]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Смысл этой программы понятен интуитивно: создается два массива — исходный (''ary'') и результирующий (''sums''), и затем массив ''sums'' заполняется суммами чисел из массива ''ary'' от 0 до текущего индекса i.&lt;br /&gt;
&lt;br /&gt;
;5-6: Особое внимание в этом примере следует уделить объявлениям переменных. Мы видим, что объявляются два [[Стандартные типы данных#Массивы|массива]] — ''ary'' и ''sums'',  причем в инструкции &amp;lt;tt&amp;gt;'''var'''&amp;lt;/tt&amp;gt; их тип никак не указывается. В этом случае работает следующее правило: если при объявлении переменной ее тип не указан, то типом переменной становится тип результата инициализатора переменной, т.е. выражения, стоящего справа от оператора '='.&lt;br /&gt;
&lt;br /&gt;
:Выражения, записанные в квадратных скобках через запятую — это встроенная в K++ конструкция, создающая объект, имеющий тип &amp;lt;tt&amp;gt;[[Стандартные типы данных#Массивы|array]]&amp;lt;/tt&amp;gt; (объявленный в [[Стандартная библиотека gide|стандартной библиотеке]]) и заполненный соответствующими значениями.&lt;br /&gt;
&lt;br /&gt;
:Оператор &amp;lt;tt&amp;gt;'''new'''&amp;lt;/tt&amp;gt; создает экземпляр произвольного класса — здесь мог бы стоять, в том числе, и пользовательский класс. В данном случае &amp;lt;tt&amp;gt;'''new'''&amp;lt;/tt&amp;gt; создает экземпляр класса &amp;lt;tt&amp;gt;[[Стандартные типы данных#Массивы|array]]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
;7: Здесь мы создаем переменную типа &amp;lt;tt&amp;gt;[[Стандартные типы данных#Целые числа|int]]&amp;lt;/tt&amp;gt;. Когда тип указан в самой конструкции &amp;lt;tt&amp;gt;'''var'''&amp;lt;/tt&amp;gt; — объект соответствующего класса создается автоматически. Таким образом, например, следующие объявления эквивалентны:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var sums = new array;&lt;br /&gt;
var sums = [ ];&lt;br /&gt;
var array sums;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
или&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var i = 0;&lt;br /&gt;
var i = new int;&lt;br /&gt;
var int i;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод &amp;lt;tt&amp;gt;push()&amp;lt;/tt&amp;gt; класса &amp;lt;tt&amp;gt;array&amp;lt;/tt&amp;gt; добавляет элемент в конец массива; &amp;lt;tt&amp;gt;size()&amp;lt;/tt&amp;gt; — возвращает количество элементов массива. Дальнейший код, думаю, объяснять не стоит.&lt;br /&gt;
&lt;br /&gt;
== Использование блоков ==&lt;br /&gt;
&lt;br /&gt;
Подобно языку Ruby, в K++ реализован механизм передачи в качестве параметра функции некоторого связанного (с вызовом) блока кода. Функция затем может вызвать этот блок один или более раз, и воспользоваться результатом, который он возвращает.&lt;br /&gt;
&lt;br /&gt;
Выглядит это следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
package block_demo;&lt;br /&gt;
&lt;br /&gt;
external console_stream STDOUT;&lt;br /&gt;
&lt;br /&gt;
function void times(int i, block b)&lt;br /&gt;
{&lt;br /&gt;
    var int n;&lt;br /&gt;
    for(n = 0; n &amp;lt; i; ++n)&lt;br /&gt;
        b(n);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
export function void main()&lt;br /&gt;
{&lt;br /&gt;
    times(3) { |i| STDOUT.print((i as string) + &amp;quot; &amp;quot;); };&lt;br /&gt;
    STDOUT.print(&amp;quot;\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат выполнения программы:&lt;br /&gt;
&lt;br /&gt;
 0 1 2&lt;br /&gt;
&lt;br /&gt;
Данный пример также демонстрирует объявление параметров функции: это делается в стиле языка C. Впрочем, тип параметра функции можно опустить — в этом случае будет сгенерирован [[Переменные#Динамическая типизация на примере Ruby|динамический код]].&lt;br /&gt;
&lt;br /&gt;
;14:В функции &amp;lt;tt&amp;gt;main()&amp;lt;/tt&amp;gt; используется специальный синтаксис для вызова функции &amp;lt;tt&amp;gt;times()&amp;lt;/tt&amp;gt;: тело блока идет сразу после оператора вызова функции. Такой синтаксис работает только в том случае, если параметр—блок объявлен последним.&lt;br /&gt;
&lt;br /&gt;
Можно было бы переписать эту конструкцию так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var b = { |i| STDOUT.print((i as string) + &amp;quot; &amp;quot;); };&lt;br /&gt;
times(3,b);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Параметры блока могут быть перечислены между символами &amp;quot;|&amp;quot; через запятую. В данном случае блок принимает один параметр — номер итерации.&lt;br /&gt;
&lt;br /&gt;
== Расширение классов ==&lt;br /&gt;
&lt;br /&gt;
Приведенный выше пример можно переписать следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
package extend_demo;&lt;br /&gt;
&lt;br /&gt;
external console_stream STDOUT;&lt;br /&gt;
&lt;br /&gt;
extend int {&lt;br /&gt;
    public const function void times(block b)&lt;br /&gt;
    {&lt;br /&gt;
        var int n;&lt;br /&gt;
        for(n = 0; n &amp;lt; this; ++n)&lt;br /&gt;
            b(n);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
export function void main()&lt;br /&gt;
{&lt;br /&gt;
    3.times() { |i| STDOUT.print((i as string) + &amp;quot; &amp;quot;); };&lt;br /&gt;
    STDOUT.print(&amp;quot;\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;5-12: Оператор &amp;lt;tt&amp;gt;'''extend'''&amp;lt;/tt&amp;gt; расширяет функционал класса — в данном случае класса &amp;lt;tt&amp;gt;[[Стандартные типы данных#Целые числа|int]]&amp;lt;/tt&amp;gt;. Его использование аналогично объявлению класса, но объявленные внутри поля, методы и операторы будут добавлены к уже существующему классу.&lt;br /&gt;
&lt;br /&gt;
: Таким образом, к классу &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;, объявленному в стандартной библиотеке, добавляется метод &amp;lt;tt&amp;gt;times()&amp;lt;/tt&amp;gt;, вызывающий связанный блок количество раз, равное текущему числу (не забываем: мы добавляем метод в класс &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;, который отвечает за хранение числа).&lt;br /&gt;
&lt;br /&gt;
;16: После такого объявления, в функции &amp;lt;tt&amp;gt;main()&amp;lt;/tt&amp;gt; мы используем уже метод &amp;lt;tt&amp;gt;times()&amp;lt;/tt&amp;gt; класса &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;: конструкция &amp;lt;tt&amp;gt;3.times()&amp;lt;/tt&amp;gt; означает создание объекта 3 класса &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt; и вызов у этого объекта метода &amp;lt;tt&amp;gt;times()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' Расширение будет работать во всем модуле, а так же во всех модулях, которые импортируют данный модуль.&lt;/div&gt;</summary>
		<author><name>KroTozeR</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:K%2B%2B</id>
		<title>Обсуждение:K++</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:K%2B%2B"/>
				<updated>2007-09-30T22:05:28Z</updated>
		
		<summary type="html">&lt;p&gt;KroTozeR: Новая: Буду периодически править грамматику по главам.--~~~~  Подправил грамматику главы &amp;quot;Введение&amp;quot;.--~~~~&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Буду периодически править грамматику по главам.--[[Участник:KroTozeR|KroTozeR]] 18:05, 30 сентября 2007 (EDT)&lt;br /&gt;
&lt;br /&gt;
Подправил грамматику главы &amp;quot;Введение&amp;quot;.--[[Участник:KroTozeR|KroTozeR]] 18:05, 30 сентября 2007 (EDT)&lt;/div&gt;</summary>
		<author><name>KroTozeR</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%98%D0%B4%D0%B5%D0%BE%D0%BB%D0%BE%D0%B3%D0%B8%D1%8F_%D1%8F%D0%B7%D1%8B%D0%BA%D0%B0</id>
		<title>Идеология языка</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%98%D0%B4%D0%B5%D0%BE%D0%BB%D0%BE%D0%B3%D0%B8%D1%8F_%D1%8F%D0%B7%D1%8B%D0%BA%D0%B0"/>
				<updated>2007-09-30T22:03:39Z</updated>
		
		<summary type="html">&lt;p&gt;KroTozeR: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Немного теории о языках программирования  ==&lt;br /&gt;
&lt;br /&gt;
В этой главе мы кратко рассмотрим основные понятия, касающиеся языков программирования, а также попробуем классифицировать язык К++ с позиции этих понятий.&lt;br /&gt;
&lt;br /&gt;
Любой язык программирования создается для решения определенного круга задач. Не существует языка, который бы позволял одинаково удобно решать задачи любого характера. Языки программирования различают по многим критериям, делят на большое количество классов и т. д. Мы же рассмотрим такой вопрос как идеологические особенности языка. Здесь, под идеологией языка понимаются некоторые конкретные подходы к отдельным вопросам, например к используемым парадигмам программирования, принципам организации памяти, отношению к исключениям и т. д.&lt;br /&gt;
&lt;br /&gt;
== Компиляторы и интерпретаторы ==&lt;br /&gt;
&lt;br /&gt;
Все языки программирования можно условно разделить на два класса: компилируемые и интерпретируемые. &lt;br /&gt;
&lt;br /&gt;
''Компилируемые языки программирования'' - это такие языки, для обработки которых используются ''компиляторы''. Они преобразуют исходный код программы в машинный код, понятный конкретному процессору и способный выполняться на нем непосредственно. К достоинствам такого подхода можно отнести то, что программа, написанная целиком на машинном коде, имеет высокую производительность. Недостатком является то, что скомпилированная программа ориентирована на конкретную архитектуру и на конкретный процессор. В результате, программа, собранная для одного процессора не будет работать на другом.&lt;br /&gt;
&lt;br /&gt;
''Интерпретируемые языки программирования'' - языки, для обработки которых используются ''интерпретаторы'', которые (в противовес компиляторам) не производят преобразования программы в машинные коды, а исполняют ее непосредственно. Конечно, производительность интерпретаторов заметно меньше, однако для выполнения, программу не требуется компилировать — она будет работать на любой платформе, где есть реализация ее интерпретатора. &lt;br /&gt;
&lt;br /&gt;
Условным это разделение было названо потому, что граница между компиляторами и интерпретаторами очень прозрачная. Практически любой компилируемый язык можно интерпретировать, в то же время многие современные интерпретаторы для повышения быстродействия производят т. н. &amp;quot;компиляцию на лету&amp;quot;, при которой исходный текст программы преобразуется в абстрактный набор инструкций или байт код, который уже выполняется.&lt;br /&gt;
&lt;br /&gt;
Язык К++ как раз относится к такой промежуточной категории языков. В результате компилирования исходного текста программы на языке К++ получается байт код модуля, который уже может быть выполнен на виртуальной машине gide. Байт код является платформенно независимым, что позволяет исполнять его на любой платформе, где существует реализация виртуальной машины.&lt;br /&gt;
&lt;br /&gt;
== Парадигменность  ==&lt;br /&gt;
&lt;br /&gt;
[http://ru.wikipedia.org Википедия] дает следующее определение понятия парадигма программирования: &lt;br /&gt;
&lt;br /&gt;
«''Парадигма программирования — это [http://ru.wikipedia.org/wiki/Парадигма парадигма], определяющая стиль программирования, иначе говоря — некоторый цельный набор идей и рекомендаций, определяющих стиль написания программ. Парадигма программирования представляет (и определяет) то, как программист видит выполнение программы. Например, в объектно-ориентированном программировании, программист рассматривает программу как набор взаимодействующих объектов, тогда как в функциональном программировании программа представляется в виде цепочки вычисления функций''».&lt;br /&gt;
&lt;br /&gt;
В общем смысле, под ''парадигмой'' можно понимать некоторый набор концепций, которые применяются при построении программы. Языки, которые позволяют писать программы в рамках нескольких парадигм, называются ''мультипарадигменными''. Например, язык К++ позволяет писать программы в структурном (совокупность функций, вызывающих друг друга), объектно-ориентированном (построение объектной модели) и смешанном (объединение обоих подходов) стилях. Следовательно, К++ тоже может служить примером мульрипарадигменного языка.&lt;br /&gt;
&lt;br /&gt;
Говоря о парадигмах, нельзя не упомянуть подлинно объектно-ориентированную природу языка К++, которая достигается уже на уровне виртуальной машины. В отличие от C++, где объектная модель является всего лишь &amp;quot;надстройкой&amp;quot; над структурной основой, язык К++, подобно Ruby и его предтечи — языку Smalltalk, придерживается принципа &amp;quot;все есть объект&amp;quot;. Это значит, что все элементы языка являются объектами. Встроенные типы данных отсутствуют, вместо них применяются классы из [[Стандартная библиотека gide|стандартной библиотеки]] языка. Это позволяет добиться удивительной гибкости при проектировании программ, вплоть до того, что программист может видоизменять даже стандартные классы, расширяя их и добавляя в них собственный функционал.&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' Более подробно, о расширениях можно почитать в кратком [[Введение, или краткий обзор#Расширение классов|обзоре]], либо в главе [[K++ как объектно-ориентированный язык#Расширения|K++ как объектно-ориентированный язык]].&lt;br /&gt;
&lt;br /&gt;
== Понятие о типизации ==&lt;br /&gt;
&lt;br /&gt;
Если говорить кратко, то под типизацией понимаются принципы организации переменных в языке. Различают ''статическую типизацию'', при которой каждой переменной ставится в соответствие ее тип, который не может быть изменен в процессе выполнения программы, и ''динамическую типизацию'', где переменные меняют свой тип от случая к случаю. К++ вводит понятие ''полудинамической типизации'', которая сочетает в себе преимущества обоих подходов и позволяет взять лучшие стороны каждого из них.&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' Более подробно понятие типизации рассмотрено в главе [[Переменные]].&lt;br /&gt;
&lt;br /&gt;
== Управление памятью ==&lt;br /&gt;
&lt;br /&gt;
Различные языки подразумевают разные способы управления памятью. Некоторые языки, например, такие как Си, предоставляют программисту прямой доступ к памяти, при этом программист сам должен следить за тем, чтобы память выделялась по мере обращения к ней и, самое главное, своевременно освобождалась после использования.&lt;br /&gt;
&lt;br /&gt;
Другие же языки, предоставляют программисту лишь тот уровень абстракции, на который они рассчитаны, при том, что вся работа по управлению памятью ложится на сам язык. Это уберегает программиста от проблем и ошибок, связанных с неправильной работой с памятью. Например, язык Java не предполагает прямого доступа к памяти виртуальной машины. Взамен, он предоставляет наборы классов, которые должны обеспечить программиста всеми необходимыми инструментами.&lt;br /&gt;
&lt;br /&gt;
Подобно Java, язык К++ так же не предполагает прямого доступа к памяти. В терминах языка программист описывает свои требования к хранилищу данных, не заботясь о том, как нужно выделять память и когда ее освобождать.&lt;br /&gt;
&lt;br /&gt;
== Понятие исключения ==&lt;br /&gt;
&lt;br /&gt;
С развитием вычислительной техники и усложнения программ возникла проблема стабильности программ. Традиционный подход, при котором функция возвращает код ошибки, превратил разработку программного обеспечения в настоящий ад, при том, что буквально каждый вызов функции приходилось оборачивать в соответствующее условие проверки кода ошибки. В некоторых областях это все же оправданно (например, ядро Диптауна с успехом применяет этот механизм в совокупности со стеком ошибок). В других областях, таких как сфера прикладного ПО такой подход менее востребован, поскольку там приводятся жесткие требования к скорости написания программ и к их качеству.&lt;br /&gt;
&lt;br /&gt;
В результате, возникла концепция исключительных ситуаций или ''исключений''. ''Механизм исключений'', — это концепция, позволяющая повысить стабильность работы программы путем внесения в нее своеобразных &amp;quot;контрольных точек&amp;quot;. Если в процессе работы программы происходит непредвиденная ситуация, например, такая как ошибка ввода-вывода или внезапное прекращение сеанса связи, то код, обнаруживший ошибку, создает специальный объект-исключение и &amp;quot;выбрасывает&amp;quot; его, то есть ''генерирует исключение''. При этом, выполнение программы прерывается и управление передается ближайшей контрольной точке, которая может перехватить это исключение и принять некоторое решение относительно того что делать дальше: например, показать пользователю сообщение об ошибке.&lt;br /&gt;
&lt;br /&gt;
Преимущество концепции исключений в том, что программисту не надо проверять каждый вызов на правильность. Он просто пишет код, предполагая что &amp;quot;все идет как надо&amp;quot;. Лишь в некоторых местах, где заранее предусматривается возможность возникновения ошибки, вставляются те самые опорные точки — перехватчики исключений. Если же ошибка произойдет, то она рано или поздно будет отловлена.&lt;/div&gt;</summary>
		<author><name>KroTozeR</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%98%D1%81%D1%82%D0%BE%D1%80%D0%B8%D1%8F_%D1%81%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D1%8F_%D1%8F%D0%B7%D1%8B%D0%BA%D0%B0</id>
		<title>История создания языка</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%98%D1%81%D1%82%D0%BE%D1%80%D0%B8%D1%8F_%D1%81%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D1%8F_%D1%8F%D0%B7%D1%8B%D0%BA%D0%B0"/>
				<updated>2007-09-30T21:50:30Z</updated>
		
		<summary type="html">&lt;p&gt;KroTozeR: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Когда мы разрабатывали платформу Диптауна, мы постоянно держали в уме следующие критерии:&lt;br /&gt;
&lt;br /&gt;
* Кроссплатформенность&lt;br /&gt;
* Расширяемость&lt;br /&gt;
* Распределенность&lt;br /&gt;
* Масштабируемость &lt;br /&gt;
* Гибкость&lt;br /&gt;
* Модульность&lt;br /&gt;
&lt;br /&gt;
То есть, система должна работать на максимально возможном количестве аппаратных платформ. При этом для портирования на новую платформу трудозатраты должны быть минимальными. Система должна быть легко расширяемой, позволяя легко и быстро интегрировать новые возможности без необходимости внесения значительных модификаций в код. Система должна быть масштабируемой, то есть она должна предоставлять возможность ее выполнения в сети с использованием множества вычислительных систем. Добавление очередного &amp;quot;узла&amp;quot; должно быть прозрачным для остальной части системы, равно как и сбой одного из существующих узлов не должен оказать значительного влияния на функционирование оставшейся части системы. Система должна быть достаточно гибкой, чтобы одну и ту же задачу возможно было решать несколькими способами. Наконец, система должна быть построена таким образом, чтобы можно было свободно заменять некоторые ее части на предоставляющие те же возможности, и чтобы эта замена так же осталась прозрачной.&lt;br /&gt;
&lt;br /&gt;
Учитывая все эти факторы, очевидно, что решить такую задачу традиционным образом практически невозможно. Различия в архитектурах систем и в особенностях их реализации сводят на нет все усилия по &amp;quot;обобщению&amp;quot; задач. Код, написанный на одной платформе, не будет работать на другой и наоборот. Пришлось бы для каждой из платформ делать свою отдельную релаизацию системы. Думаю, что Читатель может себе представить, во что обошлась бы разработка и самое главное поддержка подобной системы.&lt;br /&gt;
&lt;br /&gt;
Решение проблемы кроется в системах абстракции и виртуализации. Вместо написания множества реализаций одной и той же системы, пишется некая система абстракции, которая представляет собой прослойку между низкоуровневым кодом конкретной платформы и высокоуровневым кодом нашей системы. Эту задачу решает библиотека OSA и ядро диптауна, которые вместе предоставляют удобный программный интерфейс для кроссплатформенной разработки программ. Однако платформа диптауна из соображений производительности написана на языке С++, который хоть и является в некоторой степени кроссплатформенным, все же не обеспечивает бинарной совместимости программ. &lt;br /&gt;
&lt;br /&gt;
Таким образом, мы подходим к третьему уровню абстракции — виртуальной машине. Виртуальная машина это вычислительная среда, которая построена целиком на программной основе и поэтому не зависит от особенностей конкретной архитектуры, будь то x86, SPARC или ARM. Виртуальная машина, подобно реальной, оперирует понятиями кода и данных. В отличие от реального процессора, кодом для виртуальной машины являются не инструкции, а байт код — набор абстрактных инструкций. Достоинством такого подхода является то, что программа, транслированная в байт код, будет выполняться на любой платформе, где есть реализация виртуальной машины. А поскольку виртуальная машина сама написана на базе кроссплатформенного кода, то это обеспечивает еще большие возможности по переносимости.&lt;br /&gt;
&lt;br /&gt;
В рамках проекта Диптаун была написана своя собственная виртуальная машина [[gide]]. Она написана целиком на нашей платформе и учитывает ее особенности. Для программирования виртуальной машины используется свой язык, похожий на ассемблер, но его применение в практических задачах сильно затруднено (сложность написания программ, а главное их отладки). Было принято решение написать язык высокого уровня, который бы компилировался в gide ассемблер. В результате этого и появился язык К++.&lt;/div&gt;</summary>
		<author><name>KroTozeR</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%9F%D1%80%D0%B5%D0%B4%D0%B8%D1%81%D0%BB%D0%BE%D0%B2%D0%B8%D0%B5</id>
		<title>Предисловие</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%9F%D1%80%D0%B5%D0%B4%D0%B8%D1%81%D0%BB%D0%BE%D0%B2%D0%B8%D0%B5"/>
				<updated>2007-09-30T21:36:22Z</updated>
		
		<summary type="html">&lt;p&gt;KroTozeR: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
В последнее время наблюдается постоянный интерес программистов к написанию собственных языков программирования. Одни видят в этом хороший способ повысить свою квалификацию, другие делают это из интереса, третьи — из желания сделать язык, отвечающий их личному пониманию того, каким же должен быть Идеальный Язык Программирования. Так или иначе, и те и другие пытаются найти компромисс между теми знаниями о языках которые были у них на момент начала работы и того что они ожидали получить в итоге. &lt;br /&gt;
&lt;br /&gt;
Некоторые программисты пытаются сделать своего рода конгломерат мыслей и идей, объединив в одном языке лучшие черты нескольких других; другие же пытаются создать что-то принципиально новое, не похожее ни на один из существующих языков программирования. Иногда это удается, тогда язык может стать новым словом в программировании и в понимании самого процесса написания программы. Таким примером может послужить идея &amp;quot;графического&amp;quot; или &amp;quot;визуального&amp;quot; программирования. В этом случае программист не пишет программу в обычном понимании этого слова, а &amp;quot;рисует&amp;quot; ее, так же как художник пишет картину. Подобно тому, как художник берет краски с палитры и переносит их на холст, программист, пишущий на визуальном языке, работает с палитрой компонентов, перенося их на рабочее поле, соединяя их связями и тем самым получая готовый Образ программы. Такой подход дает существенный выигрыш в том плане, что мозг программиста работает в естественной для него среде — среде образов, объектов и взаимосвязей, что, в конечном счете, положительно сказывается на эффективности работы программиста и на сокращении трудозатрат, необходимых на получение качественной программы. Конечно, многие могут оспорить это заявление и привести тысячу доводов в защиту &amp;quot;классического&amp;quot; подхода, при котором программист оперирует только текстовым редактором и, конечно, собственным воображением. Каждая задача, каждая проблема может быть решена несколькими путями, с использованием различных инструментов. Какие из них более эффективные или удобные, решать все же самому программисту. &lt;br /&gt;
&lt;br /&gt;
Однако такие нововведения случаются сравнительно редко. Гораздо чаще происходит своеобразное &amp;quot;изобретение велосипеда&amp;quot;, при котором новоиспеченный язык программирования не претендует на место таких &amp;quot;монстров&amp;quot; как С++ или Perl. Взамен, он решает некоторые конкретные проблемы, предлагает свои решения по обеспечению удобства написания кода и его последующей отладки.&lt;br /&gt;
&lt;br /&gt;
В этом смысле, язык К++ не является исключением. При написании его мы не старались сделать что-то принципиально новое, а скорее хотели переосмыслить наше понимание языков программирования. Мы хотели сохранить лучшие черты, которые мы нашли в других языках и в то же время постараться органично совместить их в нашем языке. Совместить так, чтобы они не противоречили друг другу и представляли собой цельную и законченную систему. Часто это было довольно сложно, поскольку исходные языки представляли собой принципиально различные системы, &amp;quot;исповедующие&amp;quot; разные идеологии. &lt;br /&gt;
&lt;br /&gt;
Язык К++ вобрал в себя строгость Паскаля, лаконичность С++, удобство Ruby, гибкость Perl и в чем-то даже &amp;quot;совершенство в простоте&amp;quot;, присущее языку Smalltalk. На самом деле, этот список можно продолжить и дальше, однако наибольшее влияние оказали именно вышеперечисленные языки. Если вы знаете один или несколько из этих языков, то по ходу изложения материала вы, скорее всего, будете подмечать знакомые места. Разумеется, чем больше вы знакомы с программированием на этих языках, тем легче вам будет освоить язык К++. &lt;br /&gt;
&lt;br /&gt;
Надеюсь, уважаемый Читатель еще не был утомлен потоком моего красноречия. Если это все-таки случилось, то вы можете вздохнуть спокойно, потому что самая философская часть книги закончилась. В будущем &amp;quot;воды&amp;quot; будет меньше, однако мы все же постараемся сохранить доверительный стиль изложения и не свалиться в пучину бездны так называемого сухого научного стиля...&lt;br /&gt;
&lt;br /&gt;
== Роль K++ в проекте Диптаун  ==&lt;br /&gt;
&lt;br /&gt;
На этот язык была возложена большая ответственность. Фактически, он является вторым языком после С++, который будет использоваться в повседневной работе разработчика платформы Диптауна. К++ будет применяться практически во всех сферах, начиная от пользовательского интерфейса и заканчивая объектами виртуального пространства (программирование ботов и аватаров, ai и др.). Отдельно стоит подчеркнуть задачу динамической генерации моделей и текстур, что, в конечном счете, позволит использовать Диптаун даже пользователям, обладающим медленным сетевым соединением (вплоть до модемного). Можно даже сказать, что этот язык является основным языком программирования под платформу Диптауна, поскольку С++ подразумевает решение задач по расширению и интеграции самой платформы в отличие от К++, который используется непосредственно для ее программирования.&lt;br /&gt;
&lt;br /&gt;
== Почему именно K++? ==&lt;br /&gt;
&lt;br /&gt;
Как это часто бывает, как идея, так и название языка пришли случайно. Первоначально так назывался экспериментальный язык одного из авторов, названный по первой букве сетевого псевдонима (или по первой букве фамилии). Плюсы указывали на некоторое сходство с С++ (с точки зрения синтаксиса и объектной природы). Затем, после разработки виртуальной машины gide, потребовался язык высокого уровня, который мог бы компилироваться в gide код. Необходимо было либо адаптировать уже существующий язык к нашим нуждам, либо написать свой. По некоторым причинам решили писать свой язык (в основном из соображений единства и целостности кода). Так вспомнили о старой разработке, которая и легла в основу данного языка. Название (раньше просто рабочее обозначение) постепенно закрепилось и заняло свое место окончательно.&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' Более подробно история создания языка описана [[История создания языка|здесь]].&lt;br /&gt;
&lt;br /&gt;
== Для кого эта книга ==&lt;br /&gt;
&lt;br /&gt;
Эта книга написана в первую очередь для тех, кто желает использовать язык К++. Книга предназначена в первую очередь для обучения собственно языку (синтаксису, принципам программирования и т.д.). Однако в ней так же будут затронуты вопросы решения конкретных практических задач, как например программирование аватаров или написание модулей для графического интерфейса системы. После прочтения этой книги вы сможете писать программы любой сложности, начиная от простейших скриптов и заканчивая сложными программами, использующими все возможности платформы Диптаун. Мы постараемся затронуть как можно больше вопросов связанных с использованием платформы. Будут рассмотрены типовые задачи и приемы их решения. &lt;br /&gt;
&lt;br /&gt;
Книга ориентирована на подготовленного читателя; предполагается, что читатель уже знаком с программированием вообще и с объектно-ориентированным программированием в частности, обладает навыками написания программ и некоторыми специальными знаниями.&lt;br /&gt;
&lt;br /&gt;
== Стиль изложения материала ==&lt;br /&gt;
&lt;br /&gt;
Если вы дочитали до этого места, то уже должны примерно себе представлять, в каком стиле написана книга. Тем не мене, стоит отметить, что авторы всячески будут стараться писать более живым языком, кое-где отходя от основной мысли и разбавляя сухой текст рассуждениями, историческими сведениями и др.&lt;br /&gt;
&lt;br /&gt;
Авторами учитывался тот факт, что книга писалась в первую очередь как онлайн-руководство; ее структура была изначально рассчитана на использование перекрестных ссылок. Везде, где это возможно, будут проставляться ссылки на другие разделы книги, а так же на дополнительные материалы, касающиеся темы изложения. Сам материал излагается в несколько этапов. Сначала дается краткий обзор темы, затем более детальное рассмотрение вопросов по отдельности. Было решено, что такой подход является более эффективным, нежели обычное, линейное изложение материала. Таким образом, книгу можно использовать и как учебник, и как справочное руководство, а читать ее можно практически с любого интересующего места.&lt;br /&gt;
&lt;br /&gt;
== Тесная взаимосвязь с gide ==&lt;br /&gt;
&lt;br /&gt;
Как уже отмечалось выше, язык К++ является высокоуровневым языком, компилирующимся в байт код [[gide]]. Хорошее понимание процессов, происходящих при компиляции, и умение читать листинги gide ассемблера позволят вам писать более эффективные программы, а так же задействовать все возможности виртуальной машины. &lt;br /&gt;
&lt;br /&gt;
Поэтому, по ходу изложения материала, в некоторых местах будут приводиться листинги как программ, написанных на К++, так и соответствующий им gide код. Это поможет более полно представлять себе, что же происходит на самом деле. Если же вы считаете, что вы еще не достаточно квалифицированны для работы с ассемблером, то смело можете пропускать эти части. Однако настоятельно рекомендуется впоследствии изучить и эти материалы.&lt;br /&gt;
&lt;br /&gt;
== Принятые обозначения ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим кратко типографские обозначения, принятые в книге. При ее написании, авторы старались придерживаться единого стиля, что должно было обеспечить лучшую читаемость материала и более легкое его восприятие.&lt;br /&gt;
&lt;br /&gt;
Важные места, на которые следует обратить внимание, выделяются '''жирным''' шрифтом, например, так выделяются примечания. Различные термины и определения выделяются ''курсивом'', таким же образом выделяются переменные в ходе описания их использования в тексте (а не в самой программе). Ключевые слова, являющиеся важной частью любого языка и несущие строго определенный смысл, выделяются &amp;lt;tt&amp;gt;'''жирным моноширинным'''&amp;lt;/tt&amp;gt; стилем. &lt;br /&gt;
&lt;br /&gt;
Имена полей функций и методов, названия классов и стандартных типов данных выделяются &amp;lt;tt&amp;gt;моноширинным&amp;lt;/tt&amp;gt; стилем. Если описываемый класс имеет свою страницу в данной книге или в другом месте, на него будет сделана ссылка. Имена методов записываются вместе с круглыми скобками позади них, чтобы их можно было визуально отличить от свойств.&lt;br /&gt;
&lt;br /&gt;
Кроме того, листинги программ записываются отдельно, причем текст программы подсвечивается так, как это принято в редакторе. Подсветка синтаксиса облегчает восприятие программы и позволяет легче выделять отдельные ее структурные элементы. Относительно длинные листинги программ будут дополняться столбцом номеров строк, для облегчения описания действия отдельных частей программы.&lt;br /&gt;
&lt;br /&gt;
Ниже приведен небольшой пример применения вышеописанных стилей (на самом деле, это вырезка из главы [[Константы]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
...с точки зрения языка, ''константы'' это те же [[переменные]], за исключением того, что однажды установленное их значение нельзя изменять. В остальном они ведут себя так же как обычные [[объекты]]: их можно использовать в арифметических выражениях, передавать в качестве [[Функции#Аргументы|параметров]] [[Функции|функциям]], использовать их [[K++ как объектно-ориентированный язык#Свойства|свойства]] и вызывать [[K++ как объектно-ориентированный язык#Методы|методы]]. Разумеется, только те, которые не изменяют состояние самого объекта.&lt;br /&gt;
&lt;br /&gt;
Объявление любой константы начинается с ключевого слова &amp;lt;tt&amp;gt;'''const'''&amp;lt;/tt&amp;gt;, за которым идут тип (можно не указывать),  [[идентификатор]] имени константы и выражение-инициализатор. &lt;br /&gt;
&lt;br /&gt;
Вот примеры объявления констант:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt; &lt;br /&gt;
const real e = 2.7182818;&lt;br /&gt;
const pi = 3.1415926;&lt;br /&gt;
const s = &amp;quot;hello world&amp;quot;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тип константы можно либо указать явно, как это происходит в случае константы ''e'', либо неявно. При этом он будет назначен как тип инициализатора: константа ''pi'' будет иметь тип числа с плавающей точкой (&amp;lt;tt&amp;gt;[[Стандартные типы данных#Числа с плавающей точкой|real]]&amp;lt;/tt&amp;gt;), а константа ''s'' — строковый тип (&amp;lt;tt&amp;gt;[[Стандартные типы данных#Строки|string]]&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' При объявлении констант следите за тем, чтобы их тип был ясно виден из строки объявления. Если выражение инициализатора представляет собой довольно сложное математическое выражение, либо содержит вызовы функций, лучше всего указать тип константы явно (как в примере с константой ''e''). Иначе, это может вызывать проблемы в будущем, при работе программы или при ее отладке. В целом ситуация такая же, что и с инициализацией переменных ([[Переменные#Типизация при инициализации|см. примечание]]).&lt;/div&gt;</summary>
		<author><name>KroTozeR</name></author>	</entry>

	</feed>