<?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=Korvin</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=Korvin"/>
		<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/Korvin"/>
		<updated>2026-05-19T06:30:29Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.20.2</generator>

	<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>2012-08-23T13:23:28Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: Правки DanielBell91 (обсуждение) откачены к версии 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>Korvin</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>2012-08-23T13:21:34Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: Правки DanielBell91 (обсуждение) откачены к версии Korvin&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>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0</id>
		<title>Заглавная страница</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0"/>
				<updated>2009-11-07T15:22:10Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* Документация */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Информация ==&lt;br /&gt;
&lt;br /&gt;
* [[О проекте]]&lt;br /&gt;
* [[Deeptown SDK]]&lt;br /&gt;
* [[Deptown Programming Contest (DPC)]]&lt;br /&gt;
* [[Задачи|Текущие задачи]]&lt;br /&gt;
* [[Bugzilla]]&lt;br /&gt;
* [[Рассылка]]&lt;br /&gt;
* [[Release Notes]]&lt;br /&gt;
* [[Обратная связь]]&lt;br /&gt;
&lt;br /&gt;
== Документация ==&lt;br /&gt;
&lt;br /&gt;
* [[K++|Язык программирования K++]]&lt;br /&gt;
* [[World Engine]]&lt;br /&gt;
* [[Платформа Gide]]&lt;br /&gt;
* [[Стандартная библиотека gide]]&lt;br /&gt;
* [[Туториалы и HOWTO]]&lt;br /&gt;
* [[Building and running from source]]&lt;br /&gt;
* [[Советы и подсказки]]&lt;br /&gt;
* [[Coreutils library]]&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%A0%D0%B0%D0%B1%D0%BE%D1%87%D0%B8%D0%B5_%D0%B7%D0%B0%D0%BC%D0%B5%D1%82%D0%BA%D0%B8</id>
		<title>Рабочие заметки</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%A0%D0%B0%D0%B1%D0%BE%D1%87%D0%B8%D0%B5_%D0%B7%D0%B0%D0%BC%D0%B5%D1%82%D0%BA%D0%B8"/>
				<updated>2009-10-31T17:09:06Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* TODO */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== TODO ==&lt;br /&gt;
&lt;br /&gt;
* Описать концепцию &amp;lt;tt&amp;gt;Proc&amp;lt;/tt&amp;gt;:&lt;br /&gt;
** Отличия от &amp;lt;tt&amp;gt;[[Closure]]&amp;lt;/tt&amp;gt;&lt;br /&gt;
** Дать ссылки в книге&lt;br /&gt;
* Частичная поддержка перегрузки функций&lt;br /&gt;
* &amp;lt;s&amp;gt;Ключевое слово &amp;lt;tt&amp;gt;'''ensure'''&amp;lt;/tt&amp;gt;&amp;lt;/s&amp;gt;&lt;br /&gt;
* Описать конструкцию (a, b, c) = [x, y, z]&lt;br /&gt;
* &amp;lt;s&amp;gt;Переделать все имена исключений в основную форму ESmthError&amp;lt;/s&amp;gt;&lt;br /&gt;
* Описать механизм примесей и его идеологию&lt;br /&gt;
** Зачем нужны&lt;br /&gt;
** Чем отличаются от обычного наследования/расширения&lt;br /&gt;
** &amp;lt;tt&amp;gt;Comparable&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Enumerable&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Operable&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Добавить строки &amp;lt;tt&amp;gt;:string&amp;lt;/tt&amp;gt; и #x в схему подсветки и ключевые слова &amp;lt;tt&amp;gt;'''ensure, to'''&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Описать необходимость приведения типов (где надо) при работе с динамическими переменными&lt;br /&gt;
* Поля в расширениях теперь можно делать (?)&lt;br /&gt;
* Пространства имен&lt;br /&gt;
* [[Классы и объекты#Расширения]], описать возможность вызова предыдущей копии метода (когда появится возможность)&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''break'''&amp;lt;/tt&amp;gt; в блоках&lt;br /&gt;
* перечисления?&lt;br /&gt;
* &amp;lt;tt&amp;gt;MyClass.MY_CONST&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;s&amp;gt;абстрактные методы&amp;lt;/s&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;
== TODO компилятора ==&lt;br /&gt;
&lt;br /&gt;
* Возможность объявлять класс до его реализации, аналогично forward declarations функций&lt;br /&gt;
&lt;br /&gt;
== Перевод контента на английский язык ==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;random&amp;gt; книжку про К++ переводить?&lt;br /&gt;
&amp;lt;Raw_mat&amp;gt; переводи&lt;br /&gt;
&amp;lt;dk&amp;gt; ну там по идее поменяется много чего&lt;br /&gt;
&amp;lt;dk&amp;gt; потому что она уже малость устарела по сравнению с текущей версией языка&lt;br /&gt;
&amp;lt;dk&amp;gt; я бы лучше сказал что надо переводить все что осталось непереведенное из блогов/статей&lt;br /&gt;
&amp;lt;dk&amp;gt;  уже книжкой стал? | эмм в смысле?&lt;br /&gt;
&amp;lt;random&amp;gt; надо план перевода чтобы кто-то координировал (Рав?) именно чтобы переводить то что надо в первую очередь и чтоб оно не менялось&lt;br /&gt;
&amp;lt;dk&amp;gt; вообще по хорошему надо не только переводить. А огранизовать процесс по английской версии сайта&lt;br /&gt;
&amp;lt;dk&amp;gt; то есть м/б написать какой то материал, который был бы необходим именно там, с учетом на западную аудиторию&lt;br /&gt;
&amp;lt;Raw_mat&amp;gt; ранд, переведи интерфейс сайта на европейские  языки&lt;br /&gt;
&amp;lt;Raw_mat&amp;gt; а еще лучше на китайский или япошский&lt;br /&gt;
&amp;lt;random&amp;gt; еще надо определиться как в вики переводные статьи оформлять (шаблон названия и связь с тегом &amp;quot;язык&amp;quot;)&lt;br /&gt;
&amp;lt;random&amp;gt; могу токо на англиский пока&lt;br /&gt;
&amp;lt;Raw_mat&amp;gt; разные поддомены вики  языковые&lt;br /&gt;
&amp;lt;Raw_mat&amp;gt; какна википедии&lt;br /&gt;
&amp;lt;random&amp;gt; я к тому что в ман вики вроде нету яз разделов надо создать тогда можно будет каждому выбирать и переводить, но так чтобы не было разнобоя&lt;br /&gt;
&amp;lt;random&amp;gt; и потом корв правильно сказал надо чтоб кто-то организовывал в целом английский имидж сайта с учетом особенностей аудитории&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Main page =&lt;br /&gt;
== Informatoion ==&lt;br /&gt;
&lt;br /&gt;
* [[About this project]]&lt;br /&gt;
* [[Deeptown SDK]]&lt;br /&gt;
* [[Tasks|Current tasks]]&lt;br /&gt;
* [[Bugzilla]]&lt;br /&gt;
* [[Our Spam]]&lt;br /&gt;
* [[Release Notes]]&lt;br /&gt;
* [[Feedback]]&lt;br /&gt;
&lt;br /&gt;
== Docs ==&lt;br /&gt;
&lt;br /&gt;
* [[K++]]&lt;br /&gt;
* [[World Engine]]&lt;br /&gt;
* [[Gide Platform]]&lt;br /&gt;
* [[gide standard lib]]&lt;br /&gt;
* [[Tutorials &amp;amp; HOWTO's]]&lt;br /&gt;
* [[Building and running from source]]&lt;br /&gt;
* [[Tips &amp;amp; Tricks]]&lt;/div&gt;</summary>
		<author><name>Korvin</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>2009-10-31T17:06:59Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* Абстрактные методы */&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;
    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;
export 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-8: В этом примере мы создаем класс &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt;, который представляет собой некоторую коробку. Мы определяем ее свойства, такие как ''материал'' и ''содержимое''.&lt;br /&gt;
&lt;br /&gt;
;11-13: Далее мы определяем класс &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;
;15-17: Мы определяем некоторую [[Функции|функцию]] для работы с нашими классами, которая будет отображать их состояние. Заметьте, что в качестве [[Функции#Аргументы|аргумента функции]] передается экземпляр класса &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt;, то есть класса-родителя. При этом мы предполагаем, что любой класс, унаследованный от базового класса, будет обладать необходимым нам интерфейсом, а именно методами получения информации о свойствах (аксессорами мы их не называем, потому что они не связаны с конкретным полем; это было бы неверно).&lt;br /&gt;
&lt;br /&gt;
;19-24: Объявляется функция &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;
В теле метода доступны все поля, методы и свойства данного класса и его предков. Например, в нижеприведенном коде, метод &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;
&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() { return F1(); }&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;
При объявлении статического метода нужно указать ключевое слово &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;
&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;'''Внимание: информация в этом разделе устарела. Необходимо обновление'''&amp;lt;/font&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;
&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;
Случается, что при проектировании интерфейсов классов, возникает желание объявить некоторый набор методов в базовом классе, однако не реализовывать их. Обычно это связано с тем, что базовый класс не располагает достаточным количеством информации или возможностей для реализации этой функции. В таких случаях прменяется спецификатор &amp;lt;tt&amp;gt;'''abstract'''&amp;lt;/tt&amp;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;. Зачастую, ошибки подобного рода обнаруживаются только во время выполнения программы.&lt;br /&gt;
&lt;br /&gt;
Наконец, объявление абстрактного метода в базовом классе, позволяет автоматически генерировать особый тип исключения: &amp;lt;tt&amp;gt;[[EAbstractError]]&amp;lt;/tt&amp;gt;. Оно возникает в случае, если была произведена попытка вызова метода объявленного абстрактным в базовом классе но не реализованом в используемом потомке. В таком случае сразу ясно, где кроется ошибка. Если бы объявления не было, то возникло бы обычное исключение о том что метод не найден. &lt;br /&gt;
&lt;br /&gt;
Примечание: Использование абстрактных методов особенно удобно при реализации [[Примеси|примесей]]. Приведем пример стандартной примеси &amp;lt;tt&amp;gt;[[Enumerable|примесь Enumerable]]&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 Enumerable {&lt;br /&gt;
public:&lt;br /&gt;
    abstract const function each(block b);&lt;br /&gt;
    abstract const function int compare(const x);&lt;br /&gt;
&lt;br /&gt;
    const function bool all(block b = identity_block) {&lt;br /&gt;
        var result = true;&lt;br /&gt;
        this.each() { |...|&lt;br /&gt;
            if (!b.invoke(args())) {&lt;br /&gt;
                result = false;&lt;br /&gt;
                break;&lt;br /&gt;
            }&lt;br /&gt;
        };&lt;br /&gt;
        return result;&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    // (Другие методы примеси)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Примесь Enumerable предоставляет классам коллекций несколько методов для итерации по элементам, выбору, поиску и возможности сортировки. Класс испольщующий примесь должен объявить у себя метод &amp;lt;tt&amp;gt;each()&amp;lt;/tt&amp;gt;, который вызывает переданный блок последовательно передавая ему элементы коллекции. Если требуется использовать методы Enumerable::max, min или алгоритм сортировки, то необходимо также реализовать соответствующий метод &amp;lt;tt&amp;gt;compare()&amp;lt;/tt&amp;gt;. Примеси эффективны там, где много различных классов могут реализовывать похожее поведение, однако наследовать их все от некотрого общего базового класса нерационально. В некотором роде, примесь это своеобразный &amp;quot;недокласс&amp;quot;, экземпляры которого не является полностью самостоятельными сущностями, но поведение методов примеси в рамках другого класса может быть разумным. Так, напирмер вышеописанная примесь &amp;lt;tt&amp;gt;Enumerable&amp;lt;/tt&amp;gt; предоставляет большое количество методов для работы с коллекциями (обработки элементов), однако она понятия не имеет, о каких именно элементах идет речь. Примесь не располагает механизмом сохранения и выборки элементов, предполагая что эта функциональность будет получена в результате &amp;quot;симбиоза&amp;quot; с классом, включающим данную примесь.&lt;br /&gt;
&lt;br /&gt;
В данном случае мы видим, что примесь явным образом объявляет абстрактные методы &amp;lt;tt&amp;gt;each()&amp;lt;/tt&amp;gt; и &amp;lt;tt&amp;gt;compare()&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;
class MyClass extends Enumerable {&lt;br /&gt;
    public const function each(block b) {&lt;br /&gt;
        b(&amp;quot;hello&amp;quot;);&lt;br /&gt;
        b(&amp;quot;to&amp;quot;);&lt;br /&gt;
        b(&amp;quot;mixin!!!&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
export function main() {&lt;br /&gt;
     var c = new MyClass;&lt;br /&gt;
     var i = 1;&lt;br /&gt;
     c.collect() { |x| i++ to string + ' ' + x; }.each() { |x| puts(x); }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Нетрудно догадаться, что результатом выполнения такой программы будут следующие строки:&lt;br /&gt;
 1 hello&lt;br /&gt;
 2 to&lt;br /&gt;
 3 mixin!!!&lt;br /&gt;
&lt;br /&gt;
Обратите внимание, что мы обращаемся с инстанцией нашего класса как с коллекцией -- вызываем методы collect() и итерируем по элементам так, как будто это массив. Основное преимущество примесей в том, что они позволяют писать очень гибкий код одновременно делая его максимально универсальным и годным для повторного использования.&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' Метод collect() объявлен в стандартной библиотеке К++ (файл kpp.kpp).&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;
puts(&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;
'''Примечание 2:''' Существует альтернативный синтаксис описания аксессоров и мутаторов, при котором код соответствующий им записывается прямо в определении самого свойства. Это выглядит так:&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 f = 1;&lt;br /&gt;
    property int read { f + 1; } write { |v| f = v; };&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
И аксессор и мутатор, представлены здесь в виде inline конструкций, схожих по описанию (и смыслу) с inline блоками. Аксессор возвращает значение поля ''f'', увеличенное на единицу, в то время как мутатор принимает некоторое значение ''v'' и записывает его в соответствующее поле без каких либо изменений.&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;
Как правило, расширения применяются к классам [[Стандартной библиотека 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;
&lt;br /&gt;
extend int {&lt;br /&gt;
    const function int GetFactorial() {&lt;br /&gt;
        var result = 1;&lt;br /&gt;
        for (var x = this; x &amp;gt; 1; x--)&lt;br /&gt;
            result *= x;&lt;br /&gt;
        return result;&lt;br /&gt;
    }&lt;br /&gt;
    property int factorial read GetFactorial;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
export function main() {&lt;br /&gt;
    puts(&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;
;3-11: Мы объявляем расширение класса &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;
;14: Здесь мы видим применение расширения в действии. Константа 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;puts()&amp;lt;/tt&amp;gt;, принимает в качестве параметра [[Стандартные типы данных#Строки|строку]], в то время как тип свойства определен как &amp;lt;tt&amp;gt;[[Стандартные типы данных#Целые числа|int]]&amp;lt;/tt&amp;gt;. В этом нет ничего странного, потому что класс &amp;lt;tt&amp;gt;int&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;
&amp;lt;!-- '''Примечание:''' При работе с расширениями существует одно важное ограничение. Расширять классы можно только методами и свойствами, но не полями. Это связано с внутренней организацией языка К++ и виртуальной машины. Дополнительно стоит отметить, что методы объявленные в расширении будут перекрывать соответствующие им методы класса (имеется в виду ситуация когда имена и наборы параметров полностью совпадают). Важно понимать, что такое перекрытие не является объявлением виртуального метода — происходит именно замещение старого метода новым. --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Смотри также ==&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%A0%D0%B0%D0%B1%D0%BE%D1%87%D0%B8%D0%B5_%D0%B7%D0%B0%D0%BC%D0%B5%D1%82%D0%BA%D0%B8</id>
		<title>Рабочие заметки</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%A0%D0%B0%D0%B1%D0%BE%D1%87%D0%B8%D0%B5_%D0%B7%D0%B0%D0%BC%D0%B5%D1%82%D0%BA%D0%B8"/>
				<updated>2009-10-30T19:39:49Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* TODO */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== TODO ==&lt;br /&gt;
&lt;br /&gt;
* Описать концепцию &amp;lt;tt&amp;gt;Proc&amp;lt;/tt&amp;gt;:&lt;br /&gt;
** Отличия от &amp;lt;tt&amp;gt;[[Closure]]&amp;lt;/tt&amp;gt;&lt;br /&gt;
** Дать ссылки в книге&lt;br /&gt;
* Частичная поддержка перегрузки функций&lt;br /&gt;
* &amp;lt;s&amp;gt;Ключевое слово &amp;lt;tt&amp;gt;'''ensure'''&amp;lt;/tt&amp;gt;&amp;lt;/s&amp;gt;&lt;br /&gt;
* Описать конструкцию (a, b, c) = [x, y, z]&lt;br /&gt;
* &amp;lt;s&amp;gt;Переделать все имена исключений в основную форму ESmthError&amp;lt;/s&amp;gt;&lt;br /&gt;
* Описать механизм примесей и его идеологию&lt;br /&gt;
** Зачем нужны&lt;br /&gt;
** Чем отличаются от обычного наследования/расширения&lt;br /&gt;
** &amp;lt;tt&amp;gt;Comparable&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Enumerable&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Operable&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Добавить строки &amp;lt;tt&amp;gt;:string&amp;lt;/tt&amp;gt; и #x в схему подсветки и ключевое слово &amp;lt;tt&amp;gt;'''ensure'''&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Описать необходимость приведения типов (где надо) при работе с динамическими переменными&lt;br /&gt;
* Поля в расширениях теперь можно делать (?)&lt;br /&gt;
* Пространства имен&lt;br /&gt;
* [[Классы и объекты#Расширения]], описать возможность вызова предыдущей копии метода (когда появится возможность)&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''break'''&amp;lt;/tt&amp;gt; в блоках&lt;br /&gt;
* перечисления?&lt;br /&gt;
* &amp;lt;tt&amp;gt;MyClass.MY_CONST&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;s&amp;gt;абстрактные методы&amp;lt;/s&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;
== TODO компилятора ==&lt;br /&gt;
&lt;br /&gt;
* Возможность объявлять класс до его реализации, аналогично forward declarations функций&lt;br /&gt;
&lt;br /&gt;
== Перевод контента на английский язык ==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;random&amp;gt; книжку про К++ переводить?&lt;br /&gt;
&amp;lt;Raw_mat&amp;gt; переводи&lt;br /&gt;
&amp;lt;dk&amp;gt; ну там по идее поменяется много чего&lt;br /&gt;
&amp;lt;dk&amp;gt; потому что она уже малость устарела по сравнению с текущей версией языка&lt;br /&gt;
&amp;lt;dk&amp;gt; я бы лучше сказал что надо переводить все что осталось непереведенное из блогов/статей&lt;br /&gt;
&amp;lt;dk&amp;gt;  уже книжкой стал? | эмм в смысле?&lt;br /&gt;
&amp;lt;random&amp;gt; надо план перевода чтобы кто-то координировал (Рав?) именно чтобы переводить то что надо в первую очередь и чтоб оно не менялось&lt;br /&gt;
&amp;lt;dk&amp;gt; вообще по хорошему надо не только переводить. А огранизовать процесс по английской версии сайта&lt;br /&gt;
&amp;lt;dk&amp;gt; то есть м/б написать какой то материал, который был бы необходим именно там, с учетом на западную аудиторию&lt;br /&gt;
&amp;lt;Raw_mat&amp;gt; ранд, переведи интерфейс сайта на европейские  языки&lt;br /&gt;
&amp;lt;Raw_mat&amp;gt; а еще лучше на китайский или япошский&lt;br /&gt;
&amp;lt;random&amp;gt; еще надо определиться как в вики переводные статьи оформлять (шаблон названия и связь с тегом &amp;quot;язык&amp;quot;)&lt;br /&gt;
&amp;lt;random&amp;gt; могу токо на англиский пока&lt;br /&gt;
&amp;lt;Raw_mat&amp;gt; разные поддомены вики  языковые&lt;br /&gt;
&amp;lt;Raw_mat&amp;gt; какна википедии&lt;br /&gt;
&amp;lt;random&amp;gt; я к тому что в ман вики вроде нету яз разделов надо создать тогда можно будет каждому выбирать и переводить, но так чтобы не было разнобоя&lt;br /&gt;
&amp;lt;random&amp;gt; и потом корв правильно сказал надо чтоб кто-то организовывал в целом английский имидж сайта с учетом особенностей аудитории&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Main page =&lt;br /&gt;
== Informatoion ==&lt;br /&gt;
&lt;br /&gt;
* [[About this project]]&lt;br /&gt;
* [[Deeptown SDK]]&lt;br /&gt;
* [[Tasks|Current tasks]]&lt;br /&gt;
* [[Bugzilla]]&lt;br /&gt;
* [[Our Spam]]&lt;br /&gt;
* [[Release Notes]]&lt;br /&gt;
* [[Feedback]]&lt;br /&gt;
&lt;br /&gt;
== Docs ==&lt;br /&gt;
&lt;br /&gt;
* [[K++]]&lt;br /&gt;
* [[World Engine]]&lt;br /&gt;
* [[Gide Platform]]&lt;br /&gt;
* [[gide standard lib]]&lt;br /&gt;
* [[Tutorials &amp;amp; HOWTO's]]&lt;br /&gt;
* [[Building and running from source]]&lt;br /&gt;
* [[Tips &amp;amp; Tricks]]&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%9E%D1%81%D0%BD%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5_%D1%81%D0%B8%D0%BD%D1%82%D0%B0%D0%BA%D1%81%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D0%B5_%D0%BA%D0%BE%D0%BD%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%86%D0%B8%D0%B8</id>
		<title>Основные синтаксические конструкции</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%9E%D1%81%D0%BD%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5_%D1%81%D0%B8%D0%BD%D1%82%D0%B0%D0%BA%D1%81%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D0%B5_%D0%BA%D0%BE%D0%BD%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%86%D0%B8%D0%B8"/>
				<updated>2009-10-30T12:05:00Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* Цикл foreach */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;В этой главе будут рассмотрены основные синтаксические конструкции, которые так или иначе присутствуют в любом современном языке программирования, будь то функциональный или объектно-ориентированный язык. Это констркции условного перехода и циклы. Без подобных конструкций (или их аналогов) невозможно написать программу, сколько-нибудь сложнее чем &amp;quot;Hello world&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Условный оператор ==&lt;br /&gt;
&lt;br /&gt;
Условный оператор — это основа основ любого языка программирования. На основании условия, то есть значения некоторого выражения, принимается решение, куда следует двигаться программе. В основе всех условных операторов лежит булева логика, при которой любое утверждение сводится к двум понятиям: истина и ложь. Если условие истинно, то управление программы движется в одну сторону. Если условие ложно — в другую. Таким образом, в каждый момент времени делается выбор всего из двух направлений. Более сложные условия строятся путем последовательного прохождения элементарных, двоичных условий.&lt;br /&gt;
&lt;br /&gt;
=== Оператор if ===&lt;br /&gt;
&lt;br /&gt;
В языке K++, для проверки условия служит оператор &amp;lt;tt&amp;gt;'''if'''&amp;lt;/tt&amp;gt;, так же называемый условным оператором. Синтаксис этого оператора знаком наверное любому человеку, который имеет хоть какое-то представление о языках программирования:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
if (/* выражение условия */) {&lt;br /&gt;
    /* тело оператора */&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;tt&amp;gt;==&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;!=&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;&amp;lt;&amp;lt;/tt&amp;gt; и т. д), если их значение истинно (то есть, объекты соответствуют указанному отношению), а так же специальное ключевое слово &amp;lt;tt&amp;gt;'''true'''&amp;lt;/tt&amp;gt;, которое считается истинным всегда. Исключением является объект типа bool, имеющий в данный момент значение &amp;lt;tt&amp;gt;'''false'''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Ложными, соответственно, считаются несозданные объекты (пустые указатели), а так же операторы отношения, если их значение ложно (объекты не соответствуют отношению). Ложными так же считаются объекты, соответствующие ключевым словам &amp;lt;tt&amp;gt;'''false'''&amp;lt;/tt&amp;gt; и &amp;lt;tt&amp;gt;'''null'''&amp;lt;/tt&amp;gt;. Опять же, исключением является объект типа bool, если он имеет значение &amp;lt;tt&amp;gt;'''true'''&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;
//Выражение                      булево значение&lt;br /&gt;
true                             true&lt;br /&gt;
false                            false&lt;br /&gt;
null                             false&lt;br /&gt;
var x; x                         false&lt;br /&gt;
var y; y = 1;                    true&lt;br /&gt;
var int z; z                     true&lt;br /&gt;
var bool x;                      false&lt;br /&gt;
var bool x; x = true;            true&lt;br /&gt;
0                                true&lt;br /&gt;
1                                true&lt;br /&gt;
&amp;quot;hello world&amp;quot;                    true&lt;br /&gt;
0 == 1                           false&lt;br /&gt;
5 &amp;lt; 6                            true&lt;br /&gt;
2 &amp;gt; 3                            false&lt;br /&gt;
5 &amp;gt;= 5                           true&lt;br /&gt;
'a' != 'b'                       true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на следующие моменты:&lt;br /&gt;
* Неинициализированная динамическая переменная ''x'' считается ложной (равна &amp;lt;tt&amp;gt;'''null'''&amp;lt;/tt&amp;gt;)&lt;br /&gt;
* Инициализированная динамическая переменная ''y'' считается истинной (объект создан)&lt;br /&gt;
* Неинициализированная статическая переменная ''z'' считается истинной (объект создан)&lt;br /&gt;
* Переменная типа &amp;lt;tt&amp;gt;bool&amp;lt;/tt&amp;gt; имеет значение по умолчанию &amp;lt;tt&amp;gt;'''false'''&amp;lt;/tt&amp;gt; (хотя объект создан)&lt;br /&gt;
* 0, так же как любой другой созданный объект считается '''истиной''', в отличие от C++. &lt;br /&gt;
* условие 5 &amp;gt;= 5 считается истиной, так как формулируется как &amp;quot;5 больше 5 '''или''' равно 5&amp;quot;&lt;br /&gt;
&lt;br /&gt;
По поводу нуля следует поговорить отдельно. C++ не является в полной мере объектно-ориентированным языком, фактически, в нем ОО система является абстракцией, позволяющей оперировать все теми же понятиями стандартных типов данных и памяти, но на более высоком уровне. Все что мы имеем на этапе выполнения программы, это кусочки памяти, которые мы считаем объектами. Поскольку числа в нем являются совершенно определенной сущностью, подобные вольности возможны.&lt;br /&gt;
&lt;br /&gt;
В языке К++ все наоборот. Все с чем он оперирует — это объекты. Провести грань между стандартными типами данных и пользовательскими невозможно. Числа, что фигурируют в программе так же являются объектами. Даже числовые константы которые записываются в выражениях — это тоже объекты (это уже было показано в [[Введение, или краткий обзор#Расширение классов|кратком обзоре]]). За основу логики языка принимается факт существования объекта. Если объекта не существует — значение ложно, если существует — истинно (кроме описанных выше исключений). Оператор &amp;lt;tt&amp;gt;'''if'''&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;
if (x) {&lt;br /&gt;
    /* код, соответствущий существованию переменной x */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Подразумевается, что тело оператора будет выполнено в случае, если передаваемый объект (вероятнее всего [[Переменные#Нетипированные (динамические) переменные|динамическая переменная]]) инициализирован и существует. Но что будет, если мы передадим в качестве объекта динамическую переменную, содержащую объект типа &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;, равный нулю? Если бы реализация языка обрабатывала значение 0 как ложь, то логика оператора &amp;lt;tt&amp;gt;'''if'''&amp;lt;/tt&amp;gt; в частости и всей программы в целом, зависела бы от фактического значения переменной, а соответственно была бы неопределенной и даже непредсказуемой. Получалось бы, что для одних переменных, оператор работает одним образом, а для других — другим. Отладка подобной программы может занять многие часы. А все из-за одной условности.&lt;br /&gt;
&lt;br /&gt;
Таким образом, можно заключить, что оператор &amp;lt;tt&amp;gt;'''if'''&amp;lt;/tt&amp;gt; следует применять для проверки логического выражения, либо для проверки существования переменной. Если мы хотим проверить равенство переменной нулю, то это необходимо делать явно:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
if (x == 0) {&lt;br /&gt;
    /* что нужно делать, если x равен 0 */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Оператор if-else ===&lt;br /&gt;
&lt;br /&gt;
Если нам необходимо организовать ''ветвление'', то есть в случае истинности, выполнить один участок кода, а в случае ложности другой, то применяется расширенная форма оператора &amp;lt;tt&amp;gt;'''if-else'''&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
if (/* выражение условия */) {&lt;br /&gt;
    /* код, соответствущий истине */&lt;br /&gt;
} else {&lt;br /&gt;
    /* код, соответствущий лжи */&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;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
if (/* условие 1 */) {&lt;br /&gt;
    /* если условие 1 истинно: */&lt;br /&gt;
    if (/* условие 2 */) {&lt;br /&gt;
        /* если условие 2 истинно */&lt;br /&gt;
    }&lt;br /&gt;
    if (/* условие 3 */) {&lt;br /&gt;
        /* если условие 3 истинно */&lt;br /&gt;
    }&lt;br /&gt;
} else {&lt;br /&gt;
    /* если условие 1 ложно: */&lt;br /&gt;
    if (/* условие 4 */) {&lt;br /&gt;
        /* если условие 4 истинно */&lt;br /&gt;
    } else {&lt;br /&gt;
        /* код, соответствущий лжи условия 4 */&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Таким образом можно строить разветвленные деревья условий, которые и реализуют алгоритмы программ.&lt;br /&gt;
&lt;br /&gt;
=== Оператор if-elsif-else ===&lt;br /&gt;
&lt;br /&gt;
Существует так же третья форма условного оператора, которая позволяет проверять несколько условий в единой, более эффективной форме. Это конструкция &amp;lt;tt&amp;gt;'''if-elsif-else'''&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
if (/* условие 1 */) {&lt;br /&gt;
    /* код, соответствущий истине условия 1*/&lt;br /&gt;
} elsif (/*условие 2*/) {&lt;br /&gt;
    /* код, соответствущий истине условия 2*/&lt;br /&gt;
...&lt;br /&gt;
} else {&lt;br /&gt;
    /* код, соответствущий лжи */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Она работает так: сначала проверяется условие 1. Если оно истинно, то выполняется код в первом блоке, а затем управление выходит за рамки всей связки. Если условие 1 ложно, то проверяется условие 2, и т. д. Таким образом, вышеописанная конструкция функционально эквивалентна следующей конструкции, однако более компактна.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
if (/* условие 1 */) {&lt;br /&gt;
    /* если условие 1 истинно */&lt;br /&gt;
} else {&lt;br /&gt;
    if (/* условие 2 */) {&lt;br /&gt;
        /* если условие 2 истинно */&lt;br /&gt;
    } else {&lt;br /&gt;
        if (/* условие 3 */) {&lt;br /&gt;
            /* если условие 3 истинно */&lt;br /&gt;
        } else {&lt;br /&gt;
           ...&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;
&lt;br /&gt;
Существует так же более лаконичная форма оператора &amp;lt;tt&amp;gt;'''if'''&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;
/* выражение */ if /* условие */;&lt;br /&gt;
&amp;lt;/source&amp;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;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var even_sum = 0;&lt;br /&gt;
for (var i = 1; i &amp;lt; 100; i++)&lt;br /&gt;
    even_sum += i if i % 2 == 0; //сумма всех четных чисел&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для проверки &amp;quot;невыполнения&amp;quot; условия есть специальная форма постфиксного оператора — &amp;lt;tt&amp;gt;'''unless'''&amp;lt;/tt&amp;gt;. Выражение при таком операторе будет выполняться только если условие ложно. Таким образом, смысл оператора прямо противоположен оператору &amp;lt;tt&amp;gt;'''if'''&amp;lt;/tt&amp;gt;. Конечно, эти два оператора взаимозаменяемы. Конструкция &amp;lt;tt&amp;gt;do_smth '''if''' x;&amp;lt;/tt&amp;gt; делает то же самое что &amp;lt;tt&amp;gt;do_smth '''unless''' !x;&amp;lt;/tt&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Перепишем предыдущий код с использованием оператора &amp;lt;tt&amp;gt;'''unless'''&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 even_sum = 0;&lt;br /&gt;
for (var i = 1; i &amp;lt; 100; i++)&lt;br /&gt;
    even_sum += i unless i % 2 != 0; //сумма всех четных чисел&lt;br /&gt;
&amp;lt;/source&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 x = 5;&lt;br /&gt;
var y = 0;&lt;br /&gt;
if (x &amp;gt; 3)&lt;br /&gt;
    y = 3;&lt;br /&gt;
else &lt;br /&gt;
    y = -1;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Не будем уточнять, зачем кому-то мог понадобиться подобный &amp;quot;гениальный&amp;quot; код, а отметим лишь то, что операция присвоения занимает 4 строки при соблюдении правил форматирования кода. В тех случаях, когда тела условного оператора представляют собой простые выражения &amp;quot;в одну строчку&amp;quot;, особенно если, как уже было сказано выше, происходит присвоение, разумно применять специальную форму условного оператора — тернарный оператор &amp;lt;tt&amp;gt;?:&amp;lt;/tt&amp;gt;. Тогда, тот же код будет выглядеть так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var x = 5;&lt;br /&gt;
var y = 0;&lt;br /&gt;
y = x &amp;gt; 5 ? 3 : -1;&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;#{ }&amp;lt;/tt&amp;gt; в строках. Можно его применять и без возврата значения, например так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
while (true) {&lt;br /&gt;
   CheckState() != State.OK ? Signal() : Sleep();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' Работать такой код будет если и &amp;lt;tt&amp;gt;Signal()&amp;lt;/tt&amp;gt; и &amp;lt;tt&amp;gt;Sleep()&amp;lt;/tt&amp;gt; возвращают значения.&lt;br /&gt;
&lt;br /&gt;
== Оператор множественного выбора (switch) ==&lt;br /&gt;
&lt;br /&gt;
В тех случаях, когда требуется сравнить значение некоторого выражения с большим количеством возможных значений, применять обычные условные операторы неразумно. Код получится громоздким и трудно читаемым, а самое главное — изменять такой код будет очень сложно. В таких случаях, на помощь программисту приходит оператор множественного выбора, или оператор &amp;lt;tt&amp;gt;'''switch'''&amp;lt;/tt&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Предположим, что перед нами стоит такая задача: функция получает некоторый числовой код ошибки и на основании него должна выполнять различные действия. В частности, выводить соответствующие сообщения. Если от нас требуется только вернуть соответствующую коду ошибки строку, проще всего и эффективнее, разумеется, применять [[Стандартные типы данных#Хеши|хеши]], но мы будем считать что требуется сделать что-то еще. &lt;br /&gt;
&lt;br /&gt;
Конструкция множественного выбора реализуется следующим образом: указывается ключевое слово &amp;lt;tt&amp;gt;'''switch'''&amp;lt;/tt&amp;gt;, после которого, в круглых скобках указывается выражение-''селектор'', которое мы будем анализировать. Затем, ставятся фигурные скобки switch-блока, в теле которого могут быть только конструкции, относящиеся непосредственно к оператору. В нашем случае это будет примерно так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
function ProcessError(const int errno) {&lt;br /&gt;
    switch (errno) {&lt;br /&gt;
        /* switch блок */ &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;'''case'''&amp;lt;/tt&amp;gt;, который записывается так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
case /* выражение сравнения */: /* обработчик */&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;
case /*условие1*/, /*условие2*/, ... /*условие N*/: /* обработчик */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В качестве условия может так же быть указан [[Стандартные типы данных#Интервалы|интервал]]. Тогда будет проверяться, попадает ли значение выражения селектора в заданный интервал. Например, если нам необходимо анализировать численное выражение, то один из операторов &amp;lt;tt&amp;gt;'''case'''&amp;lt;/tt&amp;gt; может выглядеть так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
case 1, 2, 5 .. 10, 12: /* обработчик */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для срабатывания обработчика достаточно, чтобы сработало хотябы одно из условий, перечисленных в списке; тогда управление будет передано коду обработчика. Обработчиком может быть либо отдельное выражение, либо блок. Во втором случае, его необходимо заключить в фигурные скобки. В отличие от C++, после обработчика управление передается за пределы оператора &amp;lt;tt&amp;gt;'''switch'''&amp;lt;/tt&amp;gt;, а не на следующее сравнение. То есть, логика работы более близка к паскалевской конструкции &amp;lt;tt&amp;gt;'''case'''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для безусловного выхода из любого места обработчика, может применяться ключевое слово &amp;lt;tt&amp;gt;'''break'''&amp;lt;/tt&amp;gt;. При этом, управление будет передано коду, следующему за оператором &amp;lt;tt&amp;gt;'''switch'''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если требуется рассмотреть отдельный случай, когда ни одно из условий не было удовлетворено (то есть, ни один из операторов &amp;lt;tt&amp;gt;'''case'''&amp;lt;/tt&amp;gt; не сработал), применяется ''действие по умолчанию''. Для этого, необходимо записать ключевое слово &amp;lt;tt&amp;gt;'''default'''&amp;lt;/tt&amp;gt;, а затем через двоеточие указать обработчик. Естественно, никакого выражения сравнения тут нет. &lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' при использовании обработчиков по умолчанию, следует иметь в виду что: &lt;br /&gt;
* на кажый оператор &amp;lt;tt&amp;gt;'''switch'''&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; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
function ProcessError(const int errno) {&lt;br /&gt;
    switch (errno) {&lt;br /&gt;
        case AGAIN: {&lt;br /&gt;
            Log(&amp;quot;требуется повтор операции&amp;quot;); &lt;br /&gt;
            /* запрашиваем у пользователя подтверждение на повтор */ &lt;br /&gt;
        }&lt;br /&gt;
        case ACCESS_DENIED: &lt;br /&gt;
            Log(&amp;quot;ошибка доступа&amp;quot;); &lt;br /&gt;
        case REQUEST_TIMEOUT, TIMEOUT: &lt;br /&gt;
            Log(&amp;quot;таймаут&amp;quot;); &lt;br /&gt;
        default:&lt;br /&gt;
            Log(&amp;quot;неизвестный код ошибки: #{errno}&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;3-6: Поскольку выражение обработчик сложное, то есть состоит более чем из одной конструкции, мы заключили его в фирурные скобки.&lt;br /&gt;
&lt;br /&gt;
;9: Для случаев REQUEST_TIMEOUT и TIMEOUT был использован один обработчик. Подразумевается, что коды, соответствующие данным ошибкам разные, но программист решил их объединить в одно целое.&lt;br /&gt;
&lt;br /&gt;
== Циклы ==&lt;br /&gt;
&lt;br /&gt;
Циклы представляют собой еще одну неотъемлемую часть любого языка программирования. Сущность циклов заключается в том, что некоторый участок кода (тело цикла), на основании некоторого условия выполняется определенное количество раз (итераций). Различают циклы с предпроверкой условия и с постпроверкой. В первом случае, сначала проверяется условие, а затем выполняется переход. Во втором случае, тело цикла выполняется как минимум один раз, после чего проверяется условие и принимается решение о повторении, либо о выходе.&lt;br /&gt;
&lt;br /&gt;
=== Цикл while ===&lt;br /&gt;
&lt;br /&gt;
Простейшим из циклов является цикл &amp;lt;tt&amp;gt;'''while'''&amp;lt;/tt&amp;gt;, который выглядит следующим образом:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
while (/*условие*/) {&lt;br /&gt;
    /* тело цикла */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Изображение:While_loop.png|thumb|left|Блок схема цикла while]] &lt;br /&gt;
&lt;br /&gt;
Цикл &amp;lt;tt&amp;gt;'''while'''&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;
&amp;lt;br clear=&amp;quot;both&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' Существует так же постфиксная форма оператора &amp;lt;tt&amp;gt;'''while'''&amp;lt;/tt&amp;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 i = 0, s = 0;&lt;br /&gt;
s += i++ while i &amp;lt; 100;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Цикл for ===&lt;br /&gt;
&lt;br /&gt;
[[Изображение:For_loop.png|thumb|left|Блок схема цикла for]] &lt;br /&gt;
Более сложным примером является цикл &amp;lt;tt&amp;gt;'''for'''&amp;lt;/tt&amp;gt;. Как правило, он применяется в случаях, когда есть некоторая переменная изменяющая свое значение в определенных пределах и сохраняющая свое значение в течение всей итерации. В конструкции цикла &amp;lt;tt&amp;gt;'''for'''&amp;lt;/tt&amp;gt; собраны все необходимые операции, что позволяет оперировать переменной более удобным образом. Опять же, исключается возможность ошибки, при которой программист забыл выполнить одну из операций. &lt;br /&gt;
&lt;br /&gt;
Цикл &amp;lt;tt&amp;gt;'''for'''&amp;lt;/tt&amp;gt; работает следующим образом. Сначала выполняется код инициализации переменной цикла (ее еще называют управляющей переменной). Как видно из блочной диаграммы, это происходит только один раз, в самом начале. Затем, проверяется условие. Если условие истинно, управление передается телу цикла. Подразумевается, что в нем будут производиться некоторые действия, учиывающие текущее значение переменной цикла. После выполнения тела цикла, производится приращение управляющей переменной. Далее управление опять передается коду проверки условия; так повторяется до тех пор пока значение выражения условия не станет ложным. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br clear=&amp;quot;both&amp;quot; /&amp;gt;&lt;br /&gt;
В отличие от паскаля, цикл &amp;lt;tt&amp;gt;'''for'''&amp;lt;/tt&amp;gt; совершенно не обязательно должен работать с числами. В роли управляющей переменной может выступать любой объект. Синтаксис оператора &amp;lt;tt&amp;gt;'''for'''&amp;lt;/tt&amp;gt; выглядит так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
for (/* инициализатор */; /* условие */ ; /* приращение */) {&lt;br /&gt;
    /* тело цикла */&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;tt&amp;gt;++&amp;lt;/tt&amp;gt; (поскольку выражение приращения выполняется отдельно от тела, здесь не имеет значения, какую форму оператора использовать).&lt;br /&gt;
&lt;br /&gt;
В зависимости от ситуации, некоторые из трех вышеперечисленных выражений могут быть опущены. Следующие циклы, по сути, являются функционально эквивалентными:&lt;br /&gt;
&lt;br /&gt;
{| width=65% align=center&lt;br /&gt;
 | &amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
for (var i = 0; i &amp;lt; 10; i++) {&lt;br /&gt;
    /* тело */ &lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
   &amp;lt;/source&amp;gt;&lt;br /&gt;
 | &amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var i = 0;&lt;br /&gt;
for (; i &amp;lt; 10; i++) {&lt;br /&gt;
    /* тело */ &lt;br /&gt;
}&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;
for (var i = 0; ; i++) {&lt;br /&gt;
    if (i &amp;gt;= 10)&lt;br /&gt;
        break; &lt;br /&gt;
    /* тело */ &lt;br /&gt;
}&lt;br /&gt;
   &amp;lt;/source&amp;gt;&lt;br /&gt;
 | &amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
for (var i = 0; i &amp;lt; 10; ) {&lt;br /&gt;
    /* тело */ &lt;br /&gt;
    i++;&lt;br /&gt;
&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;
Ключевое слово &amp;lt;tt&amp;gt;'''break'''&amp;lt;/tt&amp;gt; служит для безусловного выхода за пределы цикла, независимо от основного условия и количества &amp;quot;оставшихся&amp;quot; итераций. Оно будет рассмотрено ниже.&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' Несмотря на то, что синтаксис цикла и логика его работы очень похожи на те, что присутствуют в языке C++, существуют и отличия. В частности, при использовании вложенных циклов, допускается (хоть и не рекомендуется) использование одного и того же имени управляющей переменной. Логика их использования соответствует логике [[Функции#Область видимости|применения локальных переменных в функциях]]:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=1&amp;gt;&lt;br /&gt;
for (var i = 1; i &amp;lt; 10; i++) {&lt;br /&gt;
    puts(&amp;quot;(1) i = #{i}&amp;quot;);&lt;br /&gt;
    for (var i = 1; i &amp;lt; 5; i++)&lt;br /&gt;
        puts(&amp;quot;(2) i = #{i}&amp;quot;);&lt;br /&gt;
    puts(&amp;quot;(3) i = #{i}&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;
Приведем несколько более практичных примеров использования цикла в различных задачах:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=1&amp;gt;&lt;br /&gt;
var s = 0, var i = 1; &lt;br /&gt;
var ary = [];&lt;br /&gt;
for ( ; i &amp;lt; 10; i++) {&lt;br /&gt;
    //используется внешняя переменная&lt;br /&gt;
    s += i;&lt;br /&gt;
    puts(&amp;quot;#{i}: s = #{s}&amp;quot;);&lt;br /&gt;
    ary.push(i);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var list lst;&lt;br /&gt;
for (var i = 0; i &amp;lt; ary.size(); ) {&lt;br /&gt;
    lst.push(ary[i]);&lt;br /&gt;
    i += 2; //приращение вынесено в тело&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var str = '[';&lt;br /&gt;
for (var li = lst.begin(); ; ++i) {&lt;br /&gt;
    if (li == lst.end()) //условие вынесено в тело&lt;br /&gt;
        break;&lt;br /&gt;
    str += &amp;quot;#{li.object}, &amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
str[str.size()-2] = &amp;quot;]&amp;quot;;&lt;br /&gt;
puts(str);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;1-8: Для демонстрации возможности частичного указания выражений цикла, приведен пример, в цикле которого отсутствует выражение-инициализатор. Для работы, цикл использует внешнюю переменную. В теле цикла считается сумма чисел от 0 до 9; результат накапливается опять же, во внешней переменной ''s''. Далее, в массив ''ary'' добавляются текущие значения управляющей переменной, то есть ''i''.  &lt;br /&gt;
&lt;br /&gt;
;10-14: В теле этого цикла, мы копируем каждый нечетный элемент массива ''ary'' в список. Обратите внимание на выражение приращения (в данном случае оно вынесено в тело цикла), которое на каждой итерации добавляет к переменной индекса 2.&lt;br /&gt;
&lt;br /&gt;
;16-23: Для отображения содержимого списка в удобной для восприятия форме, мы используем строковую переменную, в котороую последовательно записываются элементы массива, отделенные друг от друга запятой. Здесь, в качестве управляющей переменной, выступает [[итератор]] списка ''lst'', который создается в выражении-инициализаторе как локальная переменная цикла.&lt;br /&gt;
&lt;br /&gt;
=== Цикл foreach ===&lt;br /&gt;
&lt;br /&gt;
В некоторых языках программирования присутствует специальная синтаксическая конструкция цикла &amp;lt;tt&amp;gt;'''foreach'''&amp;lt;/tt&amp;gt;. Как правило, она применяется в случаях, когда необходимо перебрать все значения некоторой коллекции и выполнить код, дословно, &amp;quot;для каждого из значений&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Учитывая то, что язык K++ ориентирован на использование [[Блоки|блоков]], непосредственная надобность в такой конструкции отпадает, поскольку ее функционал с успехом может быть реализован и даже превзойден стандартными методами коллекций, такими как &amp;lt;tt&amp;gt;each()&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;each_pair()&amp;lt;/tt&amp;gt; и &amp;lt;tt&amp;gt;each_with_index()&amp;lt;/tt&amp;gt;. Первый метод делает ровно то же самое что и традиционная конструкция &amp;lt;tt&amp;gt;'''foreach'''&amp;lt;/tt&amp;gt;, второй вызывает блок, передавая ему пару из индекса и соответствующему индексу элемента из коллекции. Третий метод передает только сам индекс.&lt;br /&gt;
&lt;br /&gt;
Тем не менее, в целях удобства программистов, была создана системная функция, с названием &amp;lt;tt&amp;gt;foreach()&amp;lt;/tt&amp;gt;, которая ведет себя подобно оператору. На деле она всего лишь вызывает метод &amp;lt;tt&amp;gt;each()&amp;lt;/tt&amp;gt; у передаваемой ей коллекции:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
function void foreach(const collection, block b) {&lt;br /&gt;
    collection.each(b);&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;tt&amp;gt;'''foreach'''&amp;lt;/tt&amp;gt; не является синтаксической конструкцией, ее следует вызывать подобно функции. Это значит, что после закрывающей фигурной скобки должна стоять точка с запятой:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var ary = [1, 2, 3];&lt;br /&gt;
var p = 1;&lt;br /&gt;
foreach (ary) { |x|&lt;br /&gt;
    p *= x;&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;tt&amp;gt;'''break'''&amp;lt;/tt&amp;gt; и &amp;lt;tt&amp;gt;'''continue'''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Ключевое слво &amp;lt;tt&amp;gt;'''break'''&amp;lt;/tt&amp;gt; применяется для принудительного завершения выполнения цикла и передачи управления коду, следующему за циклом. Напротив, ключевое слво &amp;lt;tt&amp;gt;'''continue'''&amp;lt;/tt&amp;gt; применяется для прерывания текущей итерации и мгновенного перехода к началу следующей. В случае цикла &amp;lt;tt&amp;gt;'''while'''&amp;lt;/tt&amp;gt;, это просто будет означать переход на код проверки условия; в случае цикла &amp;lt;tt&amp;gt;'''for'''&amp;lt;/tt&amp;gt; — переход на код приращения управляющей переменной, с последующим переходом на код проверки условия.&lt;br /&gt;
&lt;br /&gt;
Например, цикл &amp;lt;tt&amp;gt;'''for'''&amp;lt;/tt&amp;gt; по умолчанию является циклом с предпроверкой условия. То есть, сначала проверяется условие, а затем либо выполняется очередная итерация, либо управление переходит за пределы цикла. Чтобы сделать из него цикл с постпроверкой условия, достаточно вынести код проверки условия в конец тела цикла:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
for (/*инициализатор*/; ; /*приращение*/) {&lt;br /&gt;
    /* тело цикла */&lt;br /&gt;
    if (/*условие*/)&lt;br /&gt;
        break;&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;
//бесконечный цикл while:&lt;br /&gt;
while (true) {&lt;br /&gt;
    /* тело бесконечного цикла */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//бесконечный цикл for:&lt;br /&gt;
for (;;) {&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;'''while'''&amp;lt;/tt&amp;gt; представляет собой булеву константу &amp;lt;tt&amp;gt;'''true'''&amp;lt;/tt&amp;gt;. Разумеется, ее значение постоянно и соответствует истине. Поскольку цикл &amp;lt;tt&amp;gt;'''while'''&amp;lt;/tt&amp;gt; повторяется до тех пор, пока значение условного выражения истинно, получается, что этот цикл будет выполняться бесконечно.&lt;br /&gt;
&lt;br /&gt;
То же самое происходит и с циклом &amp;lt;tt&amp;gt;'''for'''&amp;lt;/tt&amp;gt;. Как уже было сказано выше, пустое выражение условия цикла соответствует истине, поэтому этот цикл тоже никогда не завершится.&lt;br /&gt;
&lt;br /&gt;
Разумеется, подлинно бесконечные циклы никому не нужны. Компьютеры хоть редко, но все же выключаются, например для обновления программного обеспечения, или улучшения материальной базы. Соответственно программы должны иметь возможность &amp;quot;аккуратного&amp;quot; выключения своими силами. Для этого, в тело бесконечных циклов добавляется код, проверяющий некоторое внешнее условие, которое становится истинным тогда, когда требуется завершить выполнение, и прерывающий цикл с помощью ключевого слова &amp;lt;tt&amp;gt;'''break'''&amp;lt;/tt&amp;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;
То же самое относится и к циклам. Фактически, низкоуровневая реализация любого цикла сводится к операциям вычисления значений и соответствующим переходам. В этом смысле, цикл &amp;lt;tt&amp;gt;'''for'''&amp;lt;/tt&amp;gt; отличается от цикла &amp;lt;tt&amp;gt;'''while'''&amp;lt;/tt&amp;gt; только тем, что в его синтаксисе уже заранее предусмотрены некоторые типовые операции, присущие большинству циклов.&lt;br /&gt;
&lt;br /&gt;
Приведем примеры, показывающие взаимозаменяемость циклов:&lt;br /&gt;
{| width=65% align=center&lt;br /&gt;
 | &amp;lt;source lang=kpp&amp;gt;&lt;br /&gt;
var s = 0;&lt;br /&gt;
for (var i = 0; i &amp;lt; 10; ++i)&lt;br /&gt;
    s += i;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
var myObject = new MyClass;&lt;br /&gt;
while (!myObject.Compacted)&lt;br /&gt;
    myObject.Compact();&lt;br /&gt;
&lt;br /&gt;
//бесконечный цикл while&lt;br /&gt;
while (true) {&lt;br /&gt;
    var need_stop = ProcessEvents();&lt;br /&gt;
    if (need_stop)&lt;br /&gt;
        break;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
 | &amp;lt;source lang=kpp&amp;gt;&lt;br /&gt;
//цикл while в роли цикла for:&lt;br /&gt;
var i = 0;&lt;br /&gt;
var s = 0;&lt;br /&gt;
while (i &amp;lt; 10)&lt;br /&gt;
    s += i++;&lt;br /&gt;
&lt;br /&gt;
//цикл for в роли цикла while&lt;br /&gt;
var myObject = new MyClass;&lt;br /&gt;
for ( ; !myObject.Compacted; )&lt;br /&gt;
    myObject.Compact();&lt;br /&gt;
&lt;br /&gt;
//бесконечный цикл for&lt;br /&gt;
for (;;) {&lt;br /&gt;
    var need_stop = ProcessEvents();&lt;br /&gt;
    if (need_stop)&lt;br /&gt;
        break;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Мы видим, что один и тот же алгоритм можно реализовать как с помощью цикла &amp;lt;tt&amp;gt;'''while'''&amp;lt;/tt&amp;gt;, так и с помощью &amp;lt;tt&amp;gt;'''for'''&amp;lt;/tt&amp;gt;. Конечно, некоторые из указанных примеров выглядят, мягко говоря, странно. Это и понятно, — каждый из циклов создавался для решения определенных задач и был ориентирован именно на них. Цикл &amp;lt;tt&amp;gt;'''for'''&amp;lt;/tt&amp;gt; создавался для задач, в которых присутствует управляющая переменнаяя, в то время как цикл &amp;lt;tt&amp;gt;'''while'''&amp;lt;/tt&amp;gt; — для задач общей логики. Какой из циклов применять в каждом случае, и какой из них в этом случае является удобнее, должен решать сам программист.&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%9E%D1%81%D0%BD%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5_%D1%81%D0%B8%D0%BD%D1%82%D0%B0%D0%BA%D1%81%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D0%B5_%D0%BA%D0%BE%D0%BD%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%86%D0%B8%D0%B8</id>
		<title>Основные синтаксические конструкции</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%9E%D1%81%D0%BD%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5_%D1%81%D0%B8%D0%BD%D1%82%D0%B0%D0%BA%D1%81%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D0%B5_%D0%BA%D0%BE%D0%BD%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%86%D0%B8%D0%B8"/>
				<updated>2009-10-30T12:03:43Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* Цикл foreach */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;В этой главе будут рассмотрены основные синтаксические конструкции, которые так или иначе присутствуют в любом современном языке программирования, будь то функциональный или объектно-ориентированный язык. Это констркции условного перехода и циклы. Без подобных конструкций (или их аналогов) невозможно написать программу, сколько-нибудь сложнее чем &amp;quot;Hello world&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Условный оператор ==&lt;br /&gt;
&lt;br /&gt;
Условный оператор — это основа основ любого языка программирования. На основании условия, то есть значения некоторого выражения, принимается решение, куда следует двигаться программе. В основе всех условных операторов лежит булева логика, при которой любое утверждение сводится к двум понятиям: истина и ложь. Если условие истинно, то управление программы движется в одну сторону. Если условие ложно — в другую. Таким образом, в каждый момент времени делается выбор всего из двух направлений. Более сложные условия строятся путем последовательного прохождения элементарных, двоичных условий.&lt;br /&gt;
&lt;br /&gt;
=== Оператор if ===&lt;br /&gt;
&lt;br /&gt;
В языке K++, для проверки условия служит оператор &amp;lt;tt&amp;gt;'''if'''&amp;lt;/tt&amp;gt;, так же называемый условным оператором. Синтаксис этого оператора знаком наверное любому человеку, который имеет хоть какое-то представление о языках программирования:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
if (/* выражение условия */) {&lt;br /&gt;
    /* тело оператора */&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;tt&amp;gt;==&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;!=&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;&amp;lt;&amp;lt;/tt&amp;gt; и т. д), если их значение истинно (то есть, объекты соответствуют указанному отношению), а так же специальное ключевое слово &amp;lt;tt&amp;gt;'''true'''&amp;lt;/tt&amp;gt;, которое считается истинным всегда. Исключением является объект типа bool, имеющий в данный момент значение &amp;lt;tt&amp;gt;'''false'''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Ложными, соответственно, считаются несозданные объекты (пустые указатели), а так же операторы отношения, если их значение ложно (объекты не соответствуют отношению). Ложными так же считаются объекты, соответствующие ключевым словам &amp;lt;tt&amp;gt;'''false'''&amp;lt;/tt&amp;gt; и &amp;lt;tt&amp;gt;'''null'''&amp;lt;/tt&amp;gt;. Опять же, исключением является объект типа bool, если он имеет значение &amp;lt;tt&amp;gt;'''true'''&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;
//Выражение                      булево значение&lt;br /&gt;
true                             true&lt;br /&gt;
false                            false&lt;br /&gt;
null                             false&lt;br /&gt;
var x; x                         false&lt;br /&gt;
var y; y = 1;                    true&lt;br /&gt;
var int z; z                     true&lt;br /&gt;
var bool x;                      false&lt;br /&gt;
var bool x; x = true;            true&lt;br /&gt;
0                                true&lt;br /&gt;
1                                true&lt;br /&gt;
&amp;quot;hello world&amp;quot;                    true&lt;br /&gt;
0 == 1                           false&lt;br /&gt;
5 &amp;lt; 6                            true&lt;br /&gt;
2 &amp;gt; 3                            false&lt;br /&gt;
5 &amp;gt;= 5                           true&lt;br /&gt;
'a' != 'b'                       true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на следующие моменты:&lt;br /&gt;
* Неинициализированная динамическая переменная ''x'' считается ложной (равна &amp;lt;tt&amp;gt;'''null'''&amp;lt;/tt&amp;gt;)&lt;br /&gt;
* Инициализированная динамическая переменная ''y'' считается истинной (объект создан)&lt;br /&gt;
* Неинициализированная статическая переменная ''z'' считается истинной (объект создан)&lt;br /&gt;
* Переменная типа &amp;lt;tt&amp;gt;bool&amp;lt;/tt&amp;gt; имеет значение по умолчанию &amp;lt;tt&amp;gt;'''false'''&amp;lt;/tt&amp;gt; (хотя объект создан)&lt;br /&gt;
* 0, так же как любой другой созданный объект считается '''истиной''', в отличие от C++. &lt;br /&gt;
* условие 5 &amp;gt;= 5 считается истиной, так как формулируется как &amp;quot;5 больше 5 '''или''' равно 5&amp;quot;&lt;br /&gt;
&lt;br /&gt;
По поводу нуля следует поговорить отдельно. C++ не является в полной мере объектно-ориентированным языком, фактически, в нем ОО система является абстракцией, позволяющей оперировать все теми же понятиями стандартных типов данных и памяти, но на более высоком уровне. Все что мы имеем на этапе выполнения программы, это кусочки памяти, которые мы считаем объектами. Поскольку числа в нем являются совершенно определенной сущностью, подобные вольности возможны.&lt;br /&gt;
&lt;br /&gt;
В языке К++ все наоборот. Все с чем он оперирует — это объекты. Провести грань между стандартными типами данных и пользовательскими невозможно. Числа, что фигурируют в программе так же являются объектами. Даже числовые константы которые записываются в выражениях — это тоже объекты (это уже было показано в [[Введение, или краткий обзор#Расширение классов|кратком обзоре]]). За основу логики языка принимается факт существования объекта. Если объекта не существует — значение ложно, если существует — истинно (кроме описанных выше исключений). Оператор &amp;lt;tt&amp;gt;'''if'''&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;
if (x) {&lt;br /&gt;
    /* код, соответствущий существованию переменной x */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Подразумевается, что тело оператора будет выполнено в случае, если передаваемый объект (вероятнее всего [[Переменные#Нетипированные (динамические) переменные|динамическая переменная]]) инициализирован и существует. Но что будет, если мы передадим в качестве объекта динамическую переменную, содержащую объект типа &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;, равный нулю? Если бы реализация языка обрабатывала значение 0 как ложь, то логика оператора &amp;lt;tt&amp;gt;'''if'''&amp;lt;/tt&amp;gt; в частости и всей программы в целом, зависела бы от фактического значения переменной, а соответственно была бы неопределенной и даже непредсказуемой. Получалось бы, что для одних переменных, оператор работает одним образом, а для других — другим. Отладка подобной программы может занять многие часы. А все из-за одной условности.&lt;br /&gt;
&lt;br /&gt;
Таким образом, можно заключить, что оператор &amp;lt;tt&amp;gt;'''if'''&amp;lt;/tt&amp;gt; следует применять для проверки логического выражения, либо для проверки существования переменной. Если мы хотим проверить равенство переменной нулю, то это необходимо делать явно:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
if (x == 0) {&lt;br /&gt;
    /* что нужно делать, если x равен 0 */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Оператор if-else ===&lt;br /&gt;
&lt;br /&gt;
Если нам необходимо организовать ''ветвление'', то есть в случае истинности, выполнить один участок кода, а в случае ложности другой, то применяется расширенная форма оператора &amp;lt;tt&amp;gt;'''if-else'''&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
if (/* выражение условия */) {&lt;br /&gt;
    /* код, соответствущий истине */&lt;br /&gt;
} else {&lt;br /&gt;
    /* код, соответствущий лжи */&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;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
if (/* условие 1 */) {&lt;br /&gt;
    /* если условие 1 истинно: */&lt;br /&gt;
    if (/* условие 2 */) {&lt;br /&gt;
        /* если условие 2 истинно */&lt;br /&gt;
    }&lt;br /&gt;
    if (/* условие 3 */) {&lt;br /&gt;
        /* если условие 3 истинно */&lt;br /&gt;
    }&lt;br /&gt;
} else {&lt;br /&gt;
    /* если условие 1 ложно: */&lt;br /&gt;
    if (/* условие 4 */) {&lt;br /&gt;
        /* если условие 4 истинно */&lt;br /&gt;
    } else {&lt;br /&gt;
        /* код, соответствущий лжи условия 4 */&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Таким образом можно строить разветвленные деревья условий, которые и реализуют алгоритмы программ.&lt;br /&gt;
&lt;br /&gt;
=== Оператор if-elsif-else ===&lt;br /&gt;
&lt;br /&gt;
Существует так же третья форма условного оператора, которая позволяет проверять несколько условий в единой, более эффективной форме. Это конструкция &amp;lt;tt&amp;gt;'''if-elsif-else'''&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
if (/* условие 1 */) {&lt;br /&gt;
    /* код, соответствущий истине условия 1*/&lt;br /&gt;
} elsif (/*условие 2*/) {&lt;br /&gt;
    /* код, соответствущий истине условия 2*/&lt;br /&gt;
...&lt;br /&gt;
} else {&lt;br /&gt;
    /* код, соответствущий лжи */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Она работает так: сначала проверяется условие 1. Если оно истинно, то выполняется код в первом блоке, а затем управление выходит за рамки всей связки. Если условие 1 ложно, то проверяется условие 2, и т. д. Таким образом, вышеописанная конструкция функционально эквивалентна следующей конструкции, однако более компактна.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
if (/* условие 1 */) {&lt;br /&gt;
    /* если условие 1 истинно */&lt;br /&gt;
} else {&lt;br /&gt;
    if (/* условие 2 */) {&lt;br /&gt;
        /* если условие 2 истинно */&lt;br /&gt;
    } else {&lt;br /&gt;
        if (/* условие 3 */) {&lt;br /&gt;
            /* если условие 3 истинно */&lt;br /&gt;
        } else {&lt;br /&gt;
           ...&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;
&lt;br /&gt;
Существует так же более лаконичная форма оператора &amp;lt;tt&amp;gt;'''if'''&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;
/* выражение */ if /* условие */;&lt;br /&gt;
&amp;lt;/source&amp;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;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var even_sum = 0;&lt;br /&gt;
for (var i = 1; i &amp;lt; 100; i++)&lt;br /&gt;
    even_sum += i if i % 2 == 0; //сумма всех четных чисел&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для проверки &amp;quot;невыполнения&amp;quot; условия есть специальная форма постфиксного оператора — &amp;lt;tt&amp;gt;'''unless'''&amp;lt;/tt&amp;gt;. Выражение при таком операторе будет выполняться только если условие ложно. Таким образом, смысл оператора прямо противоположен оператору &amp;lt;tt&amp;gt;'''if'''&amp;lt;/tt&amp;gt;. Конечно, эти два оператора взаимозаменяемы. Конструкция &amp;lt;tt&amp;gt;do_smth '''if''' x;&amp;lt;/tt&amp;gt; делает то же самое что &amp;lt;tt&amp;gt;do_smth '''unless''' !x;&amp;lt;/tt&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Перепишем предыдущий код с использованием оператора &amp;lt;tt&amp;gt;'''unless'''&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 even_sum = 0;&lt;br /&gt;
for (var i = 1; i &amp;lt; 100; i++)&lt;br /&gt;
    even_sum += i unless i % 2 != 0; //сумма всех четных чисел&lt;br /&gt;
&amp;lt;/source&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 x = 5;&lt;br /&gt;
var y = 0;&lt;br /&gt;
if (x &amp;gt; 3)&lt;br /&gt;
    y = 3;&lt;br /&gt;
else &lt;br /&gt;
    y = -1;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Не будем уточнять, зачем кому-то мог понадобиться подобный &amp;quot;гениальный&amp;quot; код, а отметим лишь то, что операция присвоения занимает 4 строки при соблюдении правил форматирования кода. В тех случаях, когда тела условного оператора представляют собой простые выражения &amp;quot;в одну строчку&amp;quot;, особенно если, как уже было сказано выше, происходит присвоение, разумно применять специальную форму условного оператора — тернарный оператор &amp;lt;tt&amp;gt;?:&amp;lt;/tt&amp;gt;. Тогда, тот же код будет выглядеть так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var x = 5;&lt;br /&gt;
var y = 0;&lt;br /&gt;
y = x &amp;gt; 5 ? 3 : -1;&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;#{ }&amp;lt;/tt&amp;gt; в строках. Можно его применять и без возврата значения, например так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
while (true) {&lt;br /&gt;
   CheckState() != State.OK ? Signal() : Sleep();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' Работать такой код будет если и &amp;lt;tt&amp;gt;Signal()&amp;lt;/tt&amp;gt; и &amp;lt;tt&amp;gt;Sleep()&amp;lt;/tt&amp;gt; возвращают значения.&lt;br /&gt;
&lt;br /&gt;
== Оператор множественного выбора (switch) ==&lt;br /&gt;
&lt;br /&gt;
В тех случаях, когда требуется сравнить значение некоторого выражения с большим количеством возможных значений, применять обычные условные операторы неразумно. Код получится громоздким и трудно читаемым, а самое главное — изменять такой код будет очень сложно. В таких случаях, на помощь программисту приходит оператор множественного выбора, или оператор &amp;lt;tt&amp;gt;'''switch'''&amp;lt;/tt&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Предположим, что перед нами стоит такая задача: функция получает некоторый числовой код ошибки и на основании него должна выполнять различные действия. В частности, выводить соответствующие сообщения. Если от нас требуется только вернуть соответствующую коду ошибки строку, проще всего и эффективнее, разумеется, применять [[Стандартные типы данных#Хеши|хеши]], но мы будем считать что требуется сделать что-то еще. &lt;br /&gt;
&lt;br /&gt;
Конструкция множественного выбора реализуется следующим образом: указывается ключевое слово &amp;lt;tt&amp;gt;'''switch'''&amp;lt;/tt&amp;gt;, после которого, в круглых скобках указывается выражение-''селектор'', которое мы будем анализировать. Затем, ставятся фигурные скобки switch-блока, в теле которого могут быть только конструкции, относящиеся непосредственно к оператору. В нашем случае это будет примерно так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
function ProcessError(const int errno) {&lt;br /&gt;
    switch (errno) {&lt;br /&gt;
        /* switch блок */ &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;'''case'''&amp;lt;/tt&amp;gt;, который записывается так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
case /* выражение сравнения */: /* обработчик */&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;
case /*условие1*/, /*условие2*/, ... /*условие N*/: /* обработчик */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В качестве условия может так же быть указан [[Стандартные типы данных#Интервалы|интервал]]. Тогда будет проверяться, попадает ли значение выражения селектора в заданный интервал. Например, если нам необходимо анализировать численное выражение, то один из операторов &amp;lt;tt&amp;gt;'''case'''&amp;lt;/tt&amp;gt; может выглядеть так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
case 1, 2, 5 .. 10, 12: /* обработчик */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для срабатывания обработчика достаточно, чтобы сработало хотябы одно из условий, перечисленных в списке; тогда управление будет передано коду обработчика. Обработчиком может быть либо отдельное выражение, либо блок. Во втором случае, его необходимо заключить в фигурные скобки. В отличие от C++, после обработчика управление передается за пределы оператора &amp;lt;tt&amp;gt;'''switch'''&amp;lt;/tt&amp;gt;, а не на следующее сравнение. То есть, логика работы более близка к паскалевской конструкции &amp;lt;tt&amp;gt;'''case'''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для безусловного выхода из любого места обработчика, может применяться ключевое слово &amp;lt;tt&amp;gt;'''break'''&amp;lt;/tt&amp;gt;. При этом, управление будет передано коду, следующему за оператором &amp;lt;tt&amp;gt;'''switch'''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если требуется рассмотреть отдельный случай, когда ни одно из условий не было удовлетворено (то есть, ни один из операторов &amp;lt;tt&amp;gt;'''case'''&amp;lt;/tt&amp;gt; не сработал), применяется ''действие по умолчанию''. Для этого, необходимо записать ключевое слово &amp;lt;tt&amp;gt;'''default'''&amp;lt;/tt&amp;gt;, а затем через двоеточие указать обработчик. Естественно, никакого выражения сравнения тут нет. &lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' при использовании обработчиков по умолчанию, следует иметь в виду что: &lt;br /&gt;
* на кажый оператор &amp;lt;tt&amp;gt;'''switch'''&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; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
function ProcessError(const int errno) {&lt;br /&gt;
    switch (errno) {&lt;br /&gt;
        case AGAIN: {&lt;br /&gt;
            Log(&amp;quot;требуется повтор операции&amp;quot;); &lt;br /&gt;
            /* запрашиваем у пользователя подтверждение на повтор */ &lt;br /&gt;
        }&lt;br /&gt;
        case ACCESS_DENIED: &lt;br /&gt;
            Log(&amp;quot;ошибка доступа&amp;quot;); &lt;br /&gt;
        case REQUEST_TIMEOUT, TIMEOUT: &lt;br /&gt;
            Log(&amp;quot;таймаут&amp;quot;); &lt;br /&gt;
        default:&lt;br /&gt;
            Log(&amp;quot;неизвестный код ошибки: #{errno}&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;3-6: Поскольку выражение обработчик сложное, то есть состоит более чем из одной конструкции, мы заключили его в фирурные скобки.&lt;br /&gt;
&lt;br /&gt;
;9: Для случаев REQUEST_TIMEOUT и TIMEOUT был использован один обработчик. Подразумевается, что коды, соответствующие данным ошибкам разные, но программист решил их объединить в одно целое.&lt;br /&gt;
&lt;br /&gt;
== Циклы ==&lt;br /&gt;
&lt;br /&gt;
Циклы представляют собой еще одну неотъемлемую часть любого языка программирования. Сущность циклов заключается в том, что некоторый участок кода (тело цикла), на основании некоторого условия выполняется определенное количество раз (итераций). Различают циклы с предпроверкой условия и с постпроверкой. В первом случае, сначала проверяется условие, а затем выполняется переход. Во втором случае, тело цикла выполняется как минимум один раз, после чего проверяется условие и принимается решение о повторении, либо о выходе.&lt;br /&gt;
&lt;br /&gt;
=== Цикл while ===&lt;br /&gt;
&lt;br /&gt;
Простейшим из циклов является цикл &amp;lt;tt&amp;gt;'''while'''&amp;lt;/tt&amp;gt;, который выглядит следующим образом:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
while (/*условие*/) {&lt;br /&gt;
    /* тело цикла */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Изображение:While_loop.png|thumb|left|Блок схема цикла while]] &lt;br /&gt;
&lt;br /&gt;
Цикл &amp;lt;tt&amp;gt;'''while'''&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;
&amp;lt;br clear=&amp;quot;both&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' Существует так же постфиксная форма оператора &amp;lt;tt&amp;gt;'''while'''&amp;lt;/tt&amp;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 i = 0, s = 0;&lt;br /&gt;
s += i++ while i &amp;lt; 100;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Цикл for ===&lt;br /&gt;
&lt;br /&gt;
[[Изображение:For_loop.png|thumb|left|Блок схема цикла for]] &lt;br /&gt;
Более сложным примером является цикл &amp;lt;tt&amp;gt;'''for'''&amp;lt;/tt&amp;gt;. Как правило, он применяется в случаях, когда есть некоторая переменная изменяющая свое значение в определенных пределах и сохраняющая свое значение в течение всей итерации. В конструкции цикла &amp;lt;tt&amp;gt;'''for'''&amp;lt;/tt&amp;gt; собраны все необходимые операции, что позволяет оперировать переменной более удобным образом. Опять же, исключается возможность ошибки, при которой программист забыл выполнить одну из операций. &lt;br /&gt;
&lt;br /&gt;
Цикл &amp;lt;tt&amp;gt;'''for'''&amp;lt;/tt&amp;gt; работает следующим образом. Сначала выполняется код инициализации переменной цикла (ее еще называют управляющей переменной). Как видно из блочной диаграммы, это происходит только один раз, в самом начале. Затем, проверяется условие. Если условие истинно, управление передается телу цикла. Подразумевается, что в нем будут производиться некоторые действия, учиывающие текущее значение переменной цикла. После выполнения тела цикла, производится приращение управляющей переменной. Далее управление опять передается коду проверки условия; так повторяется до тех пор пока значение выражения условия не станет ложным. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br clear=&amp;quot;both&amp;quot; /&amp;gt;&lt;br /&gt;
В отличие от паскаля, цикл &amp;lt;tt&amp;gt;'''for'''&amp;lt;/tt&amp;gt; совершенно не обязательно должен работать с числами. В роли управляющей переменной может выступать любой объект. Синтаксис оператора &amp;lt;tt&amp;gt;'''for'''&amp;lt;/tt&amp;gt; выглядит так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
for (/* инициализатор */; /* условие */ ; /* приращение */) {&lt;br /&gt;
    /* тело цикла */&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;tt&amp;gt;++&amp;lt;/tt&amp;gt; (поскольку выражение приращения выполняется отдельно от тела, здесь не имеет значения, какую форму оператора использовать).&lt;br /&gt;
&lt;br /&gt;
В зависимости от ситуации, некоторые из трех вышеперечисленных выражений могут быть опущены. Следующие циклы, по сути, являются функционально эквивалентными:&lt;br /&gt;
&lt;br /&gt;
{| width=65% align=center&lt;br /&gt;
 | &amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
for (var i = 0; i &amp;lt; 10; i++) {&lt;br /&gt;
    /* тело */ &lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
   &amp;lt;/source&amp;gt;&lt;br /&gt;
 | &amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var i = 0;&lt;br /&gt;
for (; i &amp;lt; 10; i++) {&lt;br /&gt;
    /* тело */ &lt;br /&gt;
}&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;
for (var i = 0; ; i++) {&lt;br /&gt;
    if (i &amp;gt;= 10)&lt;br /&gt;
        break; &lt;br /&gt;
    /* тело */ &lt;br /&gt;
}&lt;br /&gt;
   &amp;lt;/source&amp;gt;&lt;br /&gt;
 | &amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
for (var i = 0; i &amp;lt; 10; ) {&lt;br /&gt;
    /* тело */ &lt;br /&gt;
    i++;&lt;br /&gt;
&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;
Ключевое слово &amp;lt;tt&amp;gt;'''break'''&amp;lt;/tt&amp;gt; служит для безусловного выхода за пределы цикла, независимо от основного условия и количества &amp;quot;оставшихся&amp;quot; итераций. Оно будет рассмотрено ниже.&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' Несмотря на то, что синтаксис цикла и логика его работы очень похожи на те, что присутствуют в языке C++, существуют и отличия. В частности, при использовании вложенных циклов, допускается (хоть и не рекомендуется) использование одного и того же имени управляющей переменной. Логика их использования соответствует логике [[Функции#Область видимости|применения локальных переменных в функциях]]:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=1&amp;gt;&lt;br /&gt;
for (var i = 1; i &amp;lt; 10; i++) {&lt;br /&gt;
    puts(&amp;quot;(1) i = #{i}&amp;quot;);&lt;br /&gt;
    for (var i = 1; i &amp;lt; 5; i++)&lt;br /&gt;
        puts(&amp;quot;(2) i = #{i}&amp;quot;);&lt;br /&gt;
    puts(&amp;quot;(3) i = #{i}&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;
Приведем несколько более практичных примеров использования цикла в различных задачах:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=1&amp;gt;&lt;br /&gt;
var s = 0, var i = 1; &lt;br /&gt;
var ary = [];&lt;br /&gt;
for ( ; i &amp;lt; 10; i++) {&lt;br /&gt;
    //используется внешняя переменная&lt;br /&gt;
    s += i;&lt;br /&gt;
    puts(&amp;quot;#{i}: s = #{s}&amp;quot;);&lt;br /&gt;
    ary.push(i);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var list lst;&lt;br /&gt;
for (var i = 0; i &amp;lt; ary.size(); ) {&lt;br /&gt;
    lst.push(ary[i]);&lt;br /&gt;
    i += 2; //приращение вынесено в тело&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var str = '[';&lt;br /&gt;
for (var li = lst.begin(); ; ++i) {&lt;br /&gt;
    if (li == lst.end()) //условие вынесено в тело&lt;br /&gt;
        break;&lt;br /&gt;
    str += &amp;quot;#{li.object}, &amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
str[str.size()-2] = &amp;quot;]&amp;quot;;&lt;br /&gt;
puts(str);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;1-8: Для демонстрации возможности частичного указания выражений цикла, приведен пример, в цикле которого отсутствует выражение-инициализатор. Для работы, цикл использует внешнюю переменную. В теле цикла считается сумма чисел от 0 до 9; результат накапливается опять же, во внешней переменной ''s''. Далее, в массив ''ary'' добавляются текущие значения управляющей переменной, то есть ''i''.  &lt;br /&gt;
&lt;br /&gt;
;10-14: В теле этого цикла, мы копируем каждый нечетный элемент массива ''ary'' в список. Обратите внимание на выражение приращения (в данном случае оно вынесено в тело цикла), которое на каждой итерации добавляет к переменной индекса 2.&lt;br /&gt;
&lt;br /&gt;
;16-23: Для отображения содержимого списка в удобной для восприятия форме, мы используем строковую переменную, в котороую последовательно записываются элементы массива, отделенные друг от друга запятой. Здесь, в качестве управляющей переменной, выступает [[итератор]] списка ''lst'', который создается в выражении-инициализаторе как локальная переменная цикла.&lt;br /&gt;
&lt;br /&gt;
=== Цикл foreach ===&lt;br /&gt;
&lt;br /&gt;
В некоторых языках программирования присутствует специальная синтаксическая конструкция цикла &amp;lt;tt&amp;gt;'''foreach'''&amp;lt;/tt&amp;gt;. Как правило, она применяется в случаях, когда необходимо перебрать все значения некоторой коллекции и выполнить код, дословно, &amp;quot;для каждого из значений&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Учитывая то, что язык K++ ориентирован на использование [[Блоки|блоков]], непосредственная надобность в такой конструкции отпадает, поскольку ее функционал с успехом может быть реализован и даже превзойден стандартными методами коллекций, такими как &amp;lt;tt&amp;gt;each()&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;each_pair()&amp;lt;/tt&amp;gt; и &amp;lt;tt&amp;gt;each_with_index()&amp;lt;/tt&amp;gt;. Первый метод делает ровно то же самое что и традиционная конструкция &amp;lt;tt&amp;gt;'''foreach'''&amp;lt;/tt&amp;gt;, второй вызывает блок, передавая ему пару из индекса и соответствующему индексу элемента из коллекции. Третий метод передает только сам индекс.&lt;br /&gt;
&lt;br /&gt;
Тем не менее, в целях удобства программистов, была создана системная функция, с названием &amp;lt;tt&amp;gt;foreach()&amp;lt;/tt&amp;gt;, которая ведет себя подобно оператору. На деле она всего лишь вызывает метод &amp;lt;tt&amp;gt;each()&amp;lt;/tt&amp;gt; у передаваемой ей коллекции:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
function void foreach(collection, block b) {&lt;br /&gt;
    collection.each(b);&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;tt&amp;gt;'''foreach'''&amp;lt;/tt&amp;gt; не является синтаксической конструкцией, ее следует вызывать подобно функции. Это значит, что после закрывающей фигурной скобки должна стоять точка с запятой:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var ary = [1, 2, 3];&lt;br /&gt;
var p = 1;&lt;br /&gt;
foreach (ary) { |x|&lt;br /&gt;
    p *= x;&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;tt&amp;gt;'''break'''&amp;lt;/tt&amp;gt; и &amp;lt;tt&amp;gt;'''continue'''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Ключевое слво &amp;lt;tt&amp;gt;'''break'''&amp;lt;/tt&amp;gt; применяется для принудительного завершения выполнения цикла и передачи управления коду, следующему за циклом. Напротив, ключевое слво &amp;lt;tt&amp;gt;'''continue'''&amp;lt;/tt&amp;gt; применяется для прерывания текущей итерации и мгновенного перехода к началу следующей. В случае цикла &amp;lt;tt&amp;gt;'''while'''&amp;lt;/tt&amp;gt;, это просто будет означать переход на код проверки условия; в случае цикла &amp;lt;tt&amp;gt;'''for'''&amp;lt;/tt&amp;gt; — переход на код приращения управляющей переменной, с последующим переходом на код проверки условия.&lt;br /&gt;
&lt;br /&gt;
Например, цикл &amp;lt;tt&amp;gt;'''for'''&amp;lt;/tt&amp;gt; по умолчанию является циклом с предпроверкой условия. То есть, сначала проверяется условие, а затем либо выполняется очередная итерация, либо управление переходит за пределы цикла. Чтобы сделать из него цикл с постпроверкой условия, достаточно вынести код проверки условия в конец тела цикла:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
for (/*инициализатор*/; ; /*приращение*/) {&lt;br /&gt;
    /* тело цикла */&lt;br /&gt;
    if (/*условие*/)&lt;br /&gt;
        break;&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;
//бесконечный цикл while:&lt;br /&gt;
while (true) {&lt;br /&gt;
    /* тело бесконечного цикла */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//бесконечный цикл for:&lt;br /&gt;
for (;;) {&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;'''while'''&amp;lt;/tt&amp;gt; представляет собой булеву константу &amp;lt;tt&amp;gt;'''true'''&amp;lt;/tt&amp;gt;. Разумеется, ее значение постоянно и соответствует истине. Поскольку цикл &amp;lt;tt&amp;gt;'''while'''&amp;lt;/tt&amp;gt; повторяется до тех пор, пока значение условного выражения истинно, получается, что этот цикл будет выполняться бесконечно.&lt;br /&gt;
&lt;br /&gt;
То же самое происходит и с циклом &amp;lt;tt&amp;gt;'''for'''&amp;lt;/tt&amp;gt;. Как уже было сказано выше, пустое выражение условия цикла соответствует истине, поэтому этот цикл тоже никогда не завершится.&lt;br /&gt;
&lt;br /&gt;
Разумеется, подлинно бесконечные циклы никому не нужны. Компьютеры хоть редко, но все же выключаются, например для обновления программного обеспечения, или улучшения материальной базы. Соответственно программы должны иметь возможность &amp;quot;аккуратного&amp;quot; выключения своими силами. Для этого, в тело бесконечных циклов добавляется код, проверяющий некоторое внешнее условие, которое становится истинным тогда, когда требуется завершить выполнение, и прерывающий цикл с помощью ключевого слова &amp;lt;tt&amp;gt;'''break'''&amp;lt;/tt&amp;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;
То же самое относится и к циклам. Фактически, низкоуровневая реализация любого цикла сводится к операциям вычисления значений и соответствующим переходам. В этом смысле, цикл &amp;lt;tt&amp;gt;'''for'''&amp;lt;/tt&amp;gt; отличается от цикла &amp;lt;tt&amp;gt;'''while'''&amp;lt;/tt&amp;gt; только тем, что в его синтаксисе уже заранее предусмотрены некоторые типовые операции, присущие большинству циклов.&lt;br /&gt;
&lt;br /&gt;
Приведем примеры, показывающие взаимозаменяемость циклов:&lt;br /&gt;
{| width=65% align=center&lt;br /&gt;
 | &amp;lt;source lang=kpp&amp;gt;&lt;br /&gt;
var s = 0;&lt;br /&gt;
for (var i = 0; i &amp;lt; 10; ++i)&lt;br /&gt;
    s += i;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
var myObject = new MyClass;&lt;br /&gt;
while (!myObject.Compacted)&lt;br /&gt;
    myObject.Compact();&lt;br /&gt;
&lt;br /&gt;
//бесконечный цикл while&lt;br /&gt;
while (true) {&lt;br /&gt;
    var need_stop = ProcessEvents();&lt;br /&gt;
    if (need_stop)&lt;br /&gt;
        break;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
 | &amp;lt;source lang=kpp&amp;gt;&lt;br /&gt;
//цикл while в роли цикла for:&lt;br /&gt;
var i = 0;&lt;br /&gt;
var s = 0;&lt;br /&gt;
while (i &amp;lt; 10)&lt;br /&gt;
    s += i++;&lt;br /&gt;
&lt;br /&gt;
//цикл for в роли цикла while&lt;br /&gt;
var myObject = new MyClass;&lt;br /&gt;
for ( ; !myObject.Compacted; )&lt;br /&gt;
    myObject.Compact();&lt;br /&gt;
&lt;br /&gt;
//бесконечный цикл for&lt;br /&gt;
for (;;) {&lt;br /&gt;
    var need_stop = ProcessEvents();&lt;br /&gt;
    if (need_stop)&lt;br /&gt;
        break;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Мы видим, что один и тот же алгоритм можно реализовать как с помощью цикла &amp;lt;tt&amp;gt;'''while'''&amp;lt;/tt&amp;gt;, так и с помощью &amp;lt;tt&amp;gt;'''for'''&amp;lt;/tt&amp;gt;. Конечно, некоторые из указанных примеров выглядят, мягко говоря, странно. Это и понятно, — каждый из циклов создавался для решения определенных задач и был ориентирован именно на них. Цикл &amp;lt;tt&amp;gt;'''for'''&amp;lt;/tt&amp;gt; создавался для задач, в которых присутствует управляющая переменнаяя, в то время как цикл &amp;lt;tt&amp;gt;'''while'''&amp;lt;/tt&amp;gt; — для задач общей логики. Какой из циклов применять в каждом случае, и какой из них в этом случае является удобнее, должен решать сам программист.&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%9E%D0%B1%D1%8A%D1%8F%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%B8_%D0%BA%D0%BE%D0%BD%D1%81%D1%82%D0%B0%D0%BD%D1%82</id>
		<title>Объявление переменных и констант</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%9E%D0%B1%D1%8A%D1%8F%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%B8_%D0%BA%D0%BE%D0%BD%D1%81%D1%82%D0%B0%D0%BD%D1%82"/>
				<updated>2009-10-28T14:30:13Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* Конструкция группового объявления */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
var x;&lt;br /&gt;
var x = &amp;quot;hello&amp;quot;;&lt;br /&gt;
var x, y;&lt;br /&gt;
var x, y = 0;&lt;br /&gt;
var int x, y;&lt;br /&gt;
var int x, real y;&lt;br /&gt;
var int x = &amp;quot;1&amp;quot;, y = 1.5;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При объявлении переменных важно понимать, что при явном указании типа переменной, он сопостовляется только идентификатору идущему сразу после него. Таким образом, строка 5 объявляет переменную ''x'' типа &amp;lt;tt&amp;gt;[[Стандартные типы данных#Целые числа|int]]&amp;lt;/tt&amp;gt;, в то время как переменная ''y'' будет иметь [[Переменные#Нетипированные (динамические) переменные|динамический тип]]. &lt;br /&gt;
&lt;br /&gt;
То же самое относится и к инициализаторам, которые ставятся в соответствие только той переменной, которая стоит слева от оператора &amp;quot;=&amp;quot;. К примеру, выражение в строке 4 будет инициализировать только переменную ''y'', в то время как переменная ''x'' не будет иметь инициализатора; то есть для переменной ''x'' объявление эквивалентно тому что записано в строке 1.&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на строку 7: переменная ''x'' имеет инициализатор типа &amp;lt;tt&amp;gt;string&amp;lt;/tt&amp;gt;, но ввиду того что тип переменной указан явным образом, переменная будет иметь тип &amp;lt;tt&amp;gt;int&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;
//Строка объявления         Тип x     Тип y      Инициализатор x  Инициализатор y&lt;br /&gt;
&lt;br /&gt;
var x;                     динамика   &lt;br /&gt;
var x = &amp;quot;hello&amp;quot;;            string                   &amp;quot;hello&amp;quot;   &lt;br /&gt;
var x, y;                  динамика  динамика&lt;br /&gt;
var x, y = 0;              динамика    int                              0&lt;br /&gt;
var int x, y;                int     динамика &lt;br /&gt;
var int x, real y;           int       real&lt;br /&gt;
var int x = &amp;quot;1&amp;quot;, y = 1.5;    int       real         &amp;quot;1&amp;quot; as int         1.5&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 x = 0;&lt;br /&gt;
var y;&lt;br /&gt;
y = 0;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения этого кода и переменная ''x'', и переменная ''y'' будут иметь значение равное 0. Более того, типы переменных в этот момент будут совпадать и равны &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;. Однако, переменная ''x'' будет иметь статический тип, в то время как переменная ''y'' — [[Переменные#Нетипированные (динамические) переменные|динамический]]. Если же мы попытаемся присвоить этим переменным другие значения, заведомо неприводимого типа, то произойдет следующее:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
x = { |x| return x + 1; };&lt;br /&gt;
y = [1, 2, 3];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В случае переменной ''x'' будет сгенерирована ошибка еще на этапе компиляции, поскольку тип переменной был назначен статически при инициализации и не может быть изменен в ходе работы программы. В случае переменной ''y'' никакой ошибки не произойдет, поскольку это динамическая переменная. В ходе присваивания, она просто изменит свой тип на &amp;lt;tt&amp;gt;[[Стандартные типы данных#Массивы и списки|array]]&amp;lt;/tt&amp;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;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;
const x;                    //неверно. требуется инициализатор&lt;br /&gt;
const x = &amp;quot;hello&amp;quot;;          //верно&lt;br /&gt;
const x, y = 0;             //неверно. константа x не инициализируется&lt;br /&gt;
const int x = &amp;quot;1&amp;quot;, y = 1.5; //верно&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;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var (x, y, z) = [1, '2', true];&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;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
class QueryResult {&lt;br /&gt;
    var FName, FAddress, FPhone;&lt;br /&gt;
public:&lt;br /&gt;
    property string name read FName;&lt;br /&gt;
    property string address read FAddresss;&lt;br /&gt;
    property string phoneNumber read FPhone;&lt;br /&gt;
    operator new(_name, _addr, _phone) { &lt;br /&gt;
        (FName, FAddress, FPhone) = [_name, _addr, _phone]; &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function SearchByName(const string Name) {&lt;br /&gt;
    // ... код обращения к БД ...&lt;br /&gt;
    // предположим, были возвращены следующие данные:&lt;br /&gt;
    var result = new QueryResult( 'Vassily Pupkin', &lt;br /&gt;
        'Бобруйская область, село Урюпинское, д. 13', '223-322');&lt;br /&gt;
    return result; &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function main() {&lt;br /&gt;
    // ...&lt;br /&gt;
    var result = SearchByName('%Pupkin%'); // делаем запрос&lt;br /&gt;
    // работаем с результатами, используя result.name, result.address и result.phoneNumber&lt;br /&gt;
    puts(&amp;quot;Телефон Васи Пупкина: #{result.phoneNumber}&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;
С использованием конструкции группового объявления, задача передачи и разбора параметров становится намного проще:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
function SearchByName(const string Name) {&lt;br /&gt;
    // ... код обращения к БД ...&lt;br /&gt;
    // ... 'Vassily Pupkin', 'Бобруйская область, село Урюпинское, д. 13', '223-322'&lt;br /&gt;
    return [ name, addr, phone ]; &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function main() {&lt;br /&gt;
    // ...&lt;br /&gt;
    var (name, addr, phone) = SearchByName('%Pupkin%'); // делаем запрос    &lt;br /&gt;
    puts(&amp;quot;Телефон Васи Пупкина: #{phone}&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;
&lt;br /&gt;
А вот простой способ разделить входную строку на подстроки и назначить каждой из них свою переменную:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var record = System.shellExecute(&amp;quot;head -1 /etc/passwd&amp;quot;); // строка вида 'root:x:0:0:root:/root:/bin/bash'&lt;br /&gt;
var (account, password, UID, GID, info, homedir, shell) = record.split(':');&lt;br /&gt;
puts(&amp;quot;Пользователь #{account} с номером #{UID} пользуется оболочкой #{shell} и хранит свои данные в #{homedir}&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод [[string#split]] возвращает массив подстрок, поэтому зная результат выполнения метода мы можем произвести нашу операцию объявления переменных. Это намного удобнее, чем обращаться к элементам по индексам, тем самым избегая ошибок и опять же делая код более читаемым.&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 x = 1, y = 2; // объявление переменных&lt;br /&gt;
(x, y) = [3, 4];  // групповое присваивание&lt;br /&gt;
(x, y) = [y, x];  // простой способ обменять значения местами&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Смотри также ==&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%9E%D0%B1%D1%8A%D1%8F%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%B8_%D0%BA%D0%BE%D0%BD%D1%81%D1%82%D0%B0%D0%BD%D1%82</id>
		<title>Объявление переменных и констант</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%9E%D0%B1%D1%8A%D1%8F%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%B8_%D0%BA%D0%BE%D0%BD%D1%81%D1%82%D0%B0%D0%BD%D1%82"/>
				<updated>2009-10-28T12:03:29Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* Конструкция группового объявления */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
var x;&lt;br /&gt;
var x = &amp;quot;hello&amp;quot;;&lt;br /&gt;
var x, y;&lt;br /&gt;
var x, y = 0;&lt;br /&gt;
var int x, y;&lt;br /&gt;
var int x, real y;&lt;br /&gt;
var int x = &amp;quot;1&amp;quot;, y = 1.5;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При объявлении переменных важно понимать, что при явном указании типа переменной, он сопостовляется только идентификатору идущему сразу после него. Таким образом, строка 5 объявляет переменную ''x'' типа &amp;lt;tt&amp;gt;[[Стандартные типы данных#Целые числа|int]]&amp;lt;/tt&amp;gt;, в то время как переменная ''y'' будет иметь [[Переменные#Нетипированные (динамические) переменные|динамический тип]]. &lt;br /&gt;
&lt;br /&gt;
То же самое относится и к инициализаторам, которые ставятся в соответствие только той переменной, которая стоит слева от оператора &amp;quot;=&amp;quot;. К примеру, выражение в строке 4 будет инициализировать только переменную ''y'', в то время как переменная ''x'' не будет иметь инициализатора; то есть для переменной ''x'' объявление эквивалентно тому что записано в строке 1.&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на строку 7: переменная ''x'' имеет инициализатор типа &amp;lt;tt&amp;gt;string&amp;lt;/tt&amp;gt;, но ввиду того что тип переменной указан явным образом, переменная будет иметь тип &amp;lt;tt&amp;gt;int&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;
//Строка объявления         Тип x     Тип y      Инициализатор x  Инициализатор y&lt;br /&gt;
&lt;br /&gt;
var x;                     динамика   &lt;br /&gt;
var x = &amp;quot;hello&amp;quot;;            string                   &amp;quot;hello&amp;quot;   &lt;br /&gt;
var x, y;                  динамика  динамика&lt;br /&gt;
var x, y = 0;              динамика    int                              0&lt;br /&gt;
var int x, y;                int     динамика &lt;br /&gt;
var int x, real y;           int       real&lt;br /&gt;
var int x = &amp;quot;1&amp;quot;, y = 1.5;    int       real         &amp;quot;1&amp;quot; as int         1.5&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 x = 0;&lt;br /&gt;
var y;&lt;br /&gt;
y = 0;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения этого кода и переменная ''x'', и переменная ''y'' будут иметь значение равное 0. Более того, типы переменных в этот момент будут совпадать и равны &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;. Однако, переменная ''x'' будет иметь статический тип, в то время как переменная ''y'' — [[Переменные#Нетипированные (динамические) переменные|динамический]]. Если же мы попытаемся присвоить этим переменным другие значения, заведомо неприводимого типа, то произойдет следующее:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
x = { |x| return x + 1; };&lt;br /&gt;
y = [1, 2, 3];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В случае переменной ''x'' будет сгенерирована ошибка еще на этапе компиляции, поскольку тип переменной был назначен статически при инициализации и не может быть изменен в ходе работы программы. В случае переменной ''y'' никакой ошибки не произойдет, поскольку это динамическая переменная. В ходе присваивания, она просто изменит свой тип на &amp;lt;tt&amp;gt;[[Стандартные типы данных#Массивы и списки|array]]&amp;lt;/tt&amp;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;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;
const x;                    //неверно. требуется инициализатор&lt;br /&gt;
const x = &amp;quot;hello&amp;quot;;          //верно&lt;br /&gt;
const x, y = 0;             //неверно. константа x не инициализируется&lt;br /&gt;
const int x = &amp;quot;1&amp;quot;, y = 1.5; //верно&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;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var (x, y, z) = [1, '2', true];&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;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
class QueryResult {&lt;br /&gt;
    var FName, FAddress, FPhone;&lt;br /&gt;
public:&lt;br /&gt;
    property string name read FName;&lt;br /&gt;
    property string address read FAddresss;&lt;br /&gt;
    property string phoneNumber read FPhone;&lt;br /&gt;
    operator new(_name, _addr, _phone) { &lt;br /&gt;
        (FName, FAddress, FPhone) = [_name, _addr, _phone]; &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function SearchByName(const string Name) {&lt;br /&gt;
    // ... код обращения к БД ...&lt;br /&gt;
    // предположим, были возвращены следующие данные:&lt;br /&gt;
    var result = new QueryResult( 'Vassily Pupkin', &lt;br /&gt;
        'Бобруйская область, село Урюпинское, д. 13', '223-322');&lt;br /&gt;
    return result; &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function main() {&lt;br /&gt;
    // ...&lt;br /&gt;
    var result = SearchByName('%Pupkin%'); // делаем запрос&lt;br /&gt;
    // работаем с результатами, используя result.name, result.address и result.phoneNumber&lt;br /&gt;
    puts(&amp;quot;Телефон Васи Пупкина: #{result.phoneNumber}&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;
С использованием конструкции группового объявления, задача передачи и разбора параметров становится намного проще:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
function SearchByName(const string Name) {&lt;br /&gt;
    // ... код обращения к БД ...&lt;br /&gt;
    // ... 'Vassily Pupkin', 'Бобруйская область, село Урюпинское, д. 13', '223-322'&lt;br /&gt;
    return [ name, addr, phone ]; &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function main() {&lt;br /&gt;
    // ...&lt;br /&gt;
    var (name, addr, phone) = SearchByName('%Pupkin%'); // делаем запрос    &lt;br /&gt;
    puts(&amp;quot;Телефон Васи Пупкина: #{phone}&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;
&lt;br /&gt;
А вот простой способ разделить входную строку на подстроки и назначить каждой из них свою переменную:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var record = System.shellExecute(&amp;quot;head -1 /etc/passwd&amp;quot;); // строка вида 'root:x:0:0:root:/root:/bin/bash'&lt;br /&gt;
var (account, password, UID, GID, info, homedir, shell) = record.split(':');&lt;br /&gt;
puts(&amp;quot;Пользователь #{account} с номером #{UID} пользуется оболочкой #{shell} и хранит свои данные в #{homedir}&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод [[string#split]] возвращает массив подстрок, поэтому зная результат выполнения метода мы можем произвести нашу операцию объявления переменных. Это намного удобнее, чем обращаться к элементам по индексам, тем самым избегая ошибок и опять же делая код более читаемым.&lt;br /&gt;
&lt;br /&gt;
== Смотри также ==&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%9E%D0%B1%D1%8A%D1%8F%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%B8_%D0%BA%D0%BE%D0%BD%D1%81%D1%82%D0%B0%D0%BD%D1%82</id>
		<title>Объявление переменных и констант</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%9E%D0%B1%D1%8A%D1%8F%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D1%8B%D1%85_%D0%B8_%D0%BA%D0%BE%D0%BD%D1%81%D1%82%D0%B0%D0%BD%D1%82"/>
				<updated>2009-10-28T11:59:00Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: Конструкция группового объявления&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
var x;&lt;br /&gt;
var x = &amp;quot;hello&amp;quot;;&lt;br /&gt;
var x, y;&lt;br /&gt;
var x, y = 0;&lt;br /&gt;
var int x, y;&lt;br /&gt;
var int x, real y;&lt;br /&gt;
var int x = &amp;quot;1&amp;quot;, y = 1.5;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При объявлении переменных важно понимать, что при явном указании типа переменной, он сопостовляется только идентификатору идущему сразу после него. Таким образом, строка 5 объявляет переменную ''x'' типа &amp;lt;tt&amp;gt;[[Стандартные типы данных#Целые числа|int]]&amp;lt;/tt&amp;gt;, в то время как переменная ''y'' будет иметь [[Переменные#Нетипированные (динамические) переменные|динамический тип]]. &lt;br /&gt;
&lt;br /&gt;
То же самое относится и к инициализаторам, которые ставятся в соответствие только той переменной, которая стоит слева от оператора &amp;quot;=&amp;quot;. К примеру, выражение в строке 4 будет инициализировать только переменную ''y'', в то время как переменная ''x'' не будет иметь инициализатора; то есть для переменной ''x'' объявление эквивалентно тому что записано в строке 1.&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на строку 7: переменная ''x'' имеет инициализатор типа &amp;lt;tt&amp;gt;string&amp;lt;/tt&amp;gt;, но ввиду того что тип переменной указан явным образом, переменная будет иметь тип &amp;lt;tt&amp;gt;int&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;
//Строка объявления         Тип x     Тип y      Инициализатор x  Инициализатор y&lt;br /&gt;
&lt;br /&gt;
var x;                     динамика   &lt;br /&gt;
var x = &amp;quot;hello&amp;quot;;            string                   &amp;quot;hello&amp;quot;   &lt;br /&gt;
var x, y;                  динамика  динамика&lt;br /&gt;
var x, y = 0;              динамика    int                              0&lt;br /&gt;
var int x, y;                int     динамика &lt;br /&gt;
var int x, real y;           int       real&lt;br /&gt;
var int x = &amp;quot;1&amp;quot;, y = 1.5;    int       real         &amp;quot;1&amp;quot; as int         1.5&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 x = 0;&lt;br /&gt;
var y;&lt;br /&gt;
y = 0;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения этого кода и переменная ''x'', и переменная ''y'' будут иметь значение равное 0. Более того, типы переменных в этот момент будут совпадать и равны &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;. Однако, переменная ''x'' будет иметь статический тип, в то время как переменная ''y'' — [[Переменные#Нетипированные (динамические) переменные|динамический]]. Если же мы попытаемся присвоить этим переменным другие значения, заведомо неприводимого типа, то произойдет следующее:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
x = { |x| return x + 1; };&lt;br /&gt;
y = [1, 2, 3];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В случае переменной ''x'' будет сгенерирована ошибка еще на этапе компиляции, поскольку тип переменной был назначен статически при инициализации и не может быть изменен в ходе работы программы. В случае переменной ''y'' никакой ошибки не произойдет, поскольку это динамическая переменная. В ходе присваивания, она просто изменит свой тип на &amp;lt;tt&amp;gt;[[Стандартные типы данных#Массивы и списки|array]]&amp;lt;/tt&amp;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;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;
const x;                    //неверно. требуется инициализатор&lt;br /&gt;
const x = &amp;quot;hello&amp;quot;;          //верно&lt;br /&gt;
const x, y = 0;             //неверно. константа x не инициализируется&lt;br /&gt;
const int x = &amp;quot;1&amp;quot;, y = 1.5; //верно&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;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var (x, y, z) = [1, '2', true];&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;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
class QueryResult {&lt;br /&gt;
    var FName, FAddress, FPhone;&lt;br /&gt;
public:&lt;br /&gt;
    property string name read FName;&lt;br /&gt;
    property string address read FAddresss;&lt;br /&gt;
    property string phoneNumber read FPhone;&lt;br /&gt;
    operator new(_name, _addr, _phone) { &lt;br /&gt;
        (FName, FAddress, FPhone) = [_name, _addr, _phone]; &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function SearchByName(const string Name) {&lt;br /&gt;
    // ... код обращения к БД ...&lt;br /&gt;
    // предположим, были возвращены следующие данные:&lt;br /&gt;
    var result = new QueryResult( 'Vassily Pupkin', &lt;br /&gt;
        'Бобруйская область, село Урюпинское, д. 13', '223-322');&lt;br /&gt;
    return result; &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function main() {&lt;br /&gt;
    // ...&lt;br /&gt;
    var result = SearchByName('%Pupkin%'); // делаем запрос&lt;br /&gt;
    // работаем с результатами, используя result.name, result.address и result.phoneNumber&lt;br /&gt;
    puts(&amp;quot;Телефон Васи Пупкина: #{result.phoneNumber}&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;
С использованием конструкции группового объявления, задача передачи и разбора параметров становится намного проще:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
function SearchByName(const string Name) {&lt;br /&gt;
    // ... код обращения к БД ...&lt;br /&gt;
    // ... 'Vassily Pupkin', 'Бобруйская область, село Урюпинское, д. 13', '223-322'&lt;br /&gt;
    return [ name, addr, phone ]; &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function main() {&lt;br /&gt;
    // ...&lt;br /&gt;
    var (name, addr, phone) = SearchByName('%Pupkin%'); // делаем запрос    &lt;br /&gt;
    puts(&amp;quot;Телефон Васи Пупкина: #{phone}&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;
&lt;br /&gt;
А вот простой способ разделить входную строку на подстроки и назначить каждой из них свою переменную:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var record = System.shellExecute(&amp;quot;head -1 /etc/passwd&amp;quot;); // строка вида 'root:x:0:0:root:/root:/bin/bash'&lt;br /&gt;
var (account, password, UID, GID, info, directory, shell) = record.split(':');&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод [[string#split]] возвращает массив подстрок, поэтому зная результат выполнения метода мы можем произвести нашу операцию объявления переменных. Это намного удобнее, чем обращаться к элементам по индексам, тем самым избегая ошибок и опять же делая код более читаемым.&lt;br /&gt;
&lt;br /&gt;
== Смотри также ==&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%A0%D0%B0%D0%B1%D0%BE%D1%87%D0%B8%D0%B5_%D0%B7%D0%B0%D0%BC%D0%B5%D1%82%D0%BA%D0%B8</id>
		<title>Рабочие заметки</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%A0%D0%B0%D0%B1%D0%BE%D1%87%D0%B8%D0%B5_%D0%B7%D0%B0%D0%BC%D0%B5%D1%82%D0%BA%D0%B8"/>
				<updated>2009-10-28T10:14:04Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* TODO */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== TODO ==&lt;br /&gt;
&lt;br /&gt;
* Описать концепцию &amp;lt;tt&amp;gt;Proc&amp;lt;/tt&amp;gt;:&lt;br /&gt;
** Отличия от &amp;lt;tt&amp;gt;[[Closure]]&amp;lt;/tt&amp;gt;&lt;br /&gt;
** Дать ссылки в книге&lt;br /&gt;
* Частичная поддержка перегрузки функций&lt;br /&gt;
* &amp;lt;s&amp;gt;Ключевое слово &amp;lt;tt&amp;gt;'''ensure'''&amp;lt;/tt&amp;gt;&amp;lt;/s&amp;gt;&lt;br /&gt;
* Описать конструкцию (a, b, c) = [x, y, z]&lt;br /&gt;
* Переделать все иемна исключений в основную форму ESmthError&lt;br /&gt;
* Описать механизм примесей и его идеологию&lt;br /&gt;
** Зачем нужны&lt;br /&gt;
** Чем отличаются от обычного наследования/расширения&lt;br /&gt;
** &amp;lt;tt&amp;gt;Comparable&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Enumerable&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Operable&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Добавить строки &amp;lt;tt&amp;gt;:string&amp;lt;/tt&amp;gt; и #x в схему подсветки и ключ слово &amp;lt;tt&amp;gt;'''ensure'''&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Описать необходимость приведения типов (где надо) при работе с динамическими переменными&lt;br /&gt;
* Поля в расширениях теперь можно делать (?)&lt;br /&gt;
* Пространства имен&lt;br /&gt;
* [[Классы и объекты#Расширения]], описать возможность вызова предыдущей копии метода (когда появится возможность)&lt;br /&gt;
* &amp;lt;tt&amp;gt;'''break'''&amp;lt;/tt&amp;gt; в блоках&lt;br /&gt;
* перечисления?&lt;br /&gt;
* &amp;lt;tt&amp;gt;MyClass.MY_CONST&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;s&amp;gt;абстрактные методы&amp;lt;/s&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;
== TODO компилятора ==&lt;br /&gt;
&lt;br /&gt;
* Возможность объявлять класс до его реализации, аналогично forward declarations функций&lt;br /&gt;
&lt;br /&gt;
== Перевод контента на английский язык ==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot; line=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;random&amp;gt; книжку про К++ переводить?&lt;br /&gt;
&amp;lt;Raw_mat&amp;gt; переводи&lt;br /&gt;
&amp;lt;dk&amp;gt; ну там по идее поменяется много чего&lt;br /&gt;
&amp;lt;dk&amp;gt; потому что она уже малость устарела по сравнению с текущей версией языка&lt;br /&gt;
&amp;lt;dk&amp;gt; я бы лучше сказал что надо переводить все что осталось непереведенное из блогов/статей&lt;br /&gt;
&amp;lt;dk&amp;gt;  уже книжкой стал? | эмм в смысле?&lt;br /&gt;
&amp;lt;random&amp;gt; надо план перевода чтобы кто-то координировал (Рав?) именно чтобы переводить то что надо в первую очередь и чтоб оно не менялось&lt;br /&gt;
&amp;lt;dk&amp;gt; вообще по хорошему надо не только переводить. А огранизовать процесс по английской версии сайта&lt;br /&gt;
&amp;lt;dk&amp;gt; то есть м/б написать какой то материал, который был бы необходим именно там, с учетом на западную аудиторию&lt;br /&gt;
&amp;lt;Raw_mat&amp;gt; ранд, переведи интерфейс сайта на европейские  языки&lt;br /&gt;
&amp;lt;Raw_mat&amp;gt; а еще лучше на китайский или япошский&lt;br /&gt;
&amp;lt;random&amp;gt; еще надо определиться как в вики переводные статьи оформлять (шаблон названия и связь с тегом &amp;quot;язык&amp;quot;)&lt;br /&gt;
&amp;lt;random&amp;gt; могу токо на англиский пока&lt;br /&gt;
&amp;lt;Raw_mat&amp;gt; разные поддомены вики  языковые&lt;br /&gt;
&amp;lt;Raw_mat&amp;gt; какна википедии&lt;br /&gt;
&amp;lt;random&amp;gt; я к тому что в ман вики вроде нету яз разделов надо создать тогда можно будет каждому выбирать и переводить, но так чтобы не было разнобоя&lt;br /&gt;
&amp;lt;random&amp;gt; и потом корв правильно сказал надо чтоб кто-то организовывал в целом английский имидж сайта с учетом особенностей аудитории&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Main page =&lt;br /&gt;
== Informatoion ==&lt;br /&gt;
&lt;br /&gt;
* [[About this project]]&lt;br /&gt;
* [[Deeptown SDK]]&lt;br /&gt;
* [[Tasks|Current tasks]]&lt;br /&gt;
* [[Bugzilla]]&lt;br /&gt;
* [[Our Spam]]&lt;br /&gt;
* [[Release Notes]]&lt;br /&gt;
* [[Feedback]]&lt;br /&gt;
&lt;br /&gt;
== Docs ==&lt;br /&gt;
&lt;br /&gt;
* [[K++]]&lt;br /&gt;
* [[World Engine]]&lt;br /&gt;
* [[Gide Platform]]&lt;br /&gt;
* [[gide standard lib]]&lt;br /&gt;
* [[Tutorials &amp;amp; HOWTO's]]&lt;br /&gt;
* [[Building and running from source]]&lt;br /&gt;
* [[Tips &amp;amp; Tricks]]&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0</id>
		<title>Заглавная страница</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0"/>
				<updated>2009-10-28T06:25:03Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: Защищена страница «Заглавная страница» ([edit=sysop] (бессрочно) [move=sysop] (бессрочно))&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Информация ==&lt;br /&gt;
&lt;br /&gt;
* [[О проекте]]&lt;br /&gt;
* [[Deeptown SDK]]&lt;br /&gt;
* [[Deptown Programming Contest (DPC)]]&lt;br /&gt;
* [[Задачи|Текущие задачи]]&lt;br /&gt;
* [[Bugzilla]]&lt;br /&gt;
* [[Рассылка]]&lt;br /&gt;
* [[Release Notes]]&lt;br /&gt;
* [[Обратная связь]]&lt;br /&gt;
&lt;br /&gt;
== Документация ==&lt;br /&gt;
&lt;br /&gt;
* [[K++]]&lt;br /&gt;
* [[World Engine]]&lt;br /&gt;
* [[Платформа Gide]]&lt;br /&gt;
* [[Стандартная библиотека gide]]&lt;br /&gt;
* [[Туториалы и HOWTO]]&lt;br /&gt;
* [[Building and running from source]]&lt;br /&gt;
* [[Советы и подсказки]]&lt;br /&gt;
* [[Coreutils library]]&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%9E%D0%B1%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0_%D0%B8%D1%81%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B9</id>
		<title>Обработка исключений</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%9E%D0%B1%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0_%D0%B8%D1%81%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B9"/>
				<updated>2009-10-28T05:32:49Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: &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;
Все вышеперечисленные события так или иначе могут произойти в ходе работы программы, однако, с точностью предсказать их практически невозможно, можно только оценить вероятность. Хорошая программа так и делает: в тех местах, где могут потенциально произойти исключительные ситуации, вставляется код, проверяющий состояние и производящий некоторые действия по &amp;quot;ликвидации последствий&amp;quot;. Например, в случае ошибки связи, программа может попытаться установить соединение заново, в то время как при ошибке внезапного конца файла, остается только уведомить об этом пользователя, показав соответствующее сообщение об ошибке.&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;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
    /* try-блок (основное тело) */&lt;br /&gt;
} catch (/* переменная для объекта исключения 1 */) {&lt;br /&gt;
    /* код перехватчика 1 */&lt;br /&gt;
} catch (/* переменная для объекта исключения 2 */) {&lt;br /&gt;
    /* код перехватчика 2 */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ключевое слово &amp;lt;tt&amp;gt;'''try'''&amp;lt;/tt&amp;gt; объявляет начало защищенного блока. Затем, идет основное тело или try-блок, в котором содержатся конструкции, соответствующие нормальной работе. В примере с файлом, здесь будет находиться код чтения содержимого файла и, возможно, его обработки. Если в ходе выполнения этого блока, возникнет исключительная ситуация, то управление будет передано одному из блоков обработки, соответствующему типу возникшего исключения (об этом чуть позже). В круглых скобках указывается имя переменной, которой будет назначен ''объект исключения'' — объект некоторого класса, который был &amp;quot;выброшен&amp;quot; из кода в качестве исключения.&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;
Код, который первым обнаруживает исключительную ситуацию (то есть, стоит у ее истоков) и желающий сообщить о ней &amp;quot;наверх&amp;quot;, должен создать объект исключения и &amp;quot;выбросить&amp;quot; его. Создается объект так же, как и любой другой объект в языке К++: либо с помощью оператора &amp;lt;tt&amp;gt;'''new'''&amp;lt;/tt&amp;gt;, либо с помощью [[Классы и объекты#Конструкторы|конструктора]] (если он предусмотрен). &amp;quot;Выбрасывание&amp;quot; объекта осуществляется с помощью специального оператора &amp;lt;tt&amp;gt;'''throw'''&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;
function Process(const int idx) {&lt;br /&gt;
    if (! idx in 5 .. 10)&lt;br /&gt;
        throw &amp;quot;индекс должен быть в диапазоне от 5 до 10&amp;quot;;&lt;br /&gt;
    /* нормальный код обработки */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В первой строке тела функции, проверяется условие, необходимое функции для работы. Если условие не выполняется, то производится генерация исключения, причем в качестве объекта исключения выступает объект строки. &lt;br /&gt;
&lt;br /&gt;
На практике применяются специальные классы распространенных исключений, которые объявлены в [[Стандартная библиотека Gide|стандартной библиотеке]]. Таким образом, все языки использующие стандартную библиотеку и умеющие работать с исключениями, смогут успешно взаимодействовать с помощью этого механизма.&lt;br /&gt;
&lt;br /&gt;
Приведем некоторые из наиболее распространенных классов исключений и поясним их назначение:&lt;br /&gt;
&lt;br /&gt;
::{| width=60%&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EInvalidCall&amp;lt;/tt&amp;gt; || неверный вызов (входные данные неверны)&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EFailed&amp;lt;/tt&amp;gt; || операция не удалась (и все тут)&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EAagain&amp;lt;/tt&amp;gt; || по тем или иным причинам требуется повтор операции&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EDenied &amp;lt;/tt&amp;gt; || действие запрещено!&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;ECancelled &amp;lt;/tt&amp;gt; || операция была отменена (например пользователем)&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EAlready&amp;lt;/tt&amp;gt; || операция уже была выполнена&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;ERangeError&amp;lt;/tt&amp;gt; || ошибка диапазона (выход значения за допустимые границы)&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EDivisionByZero&amp;lt;/tt&amp;gt; || арифметическая ошибка деления на ноль&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;ETimeout  &amp;lt;/tt&amp;gt; || истекло время ожидания чего-либо&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EStreamError&amp;lt;/tt&amp;gt; || ошибка [[потока]]&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;ERegexpError&amp;lt;/tt&amp;gt; || ошибка при разборе [[регулярного выражения]]&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EAbstractError&amp;lt;/tt&amp;gt; || попытка вызова [[Классы и объекты#Методы|абстрактного метода]]&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Здесь приведены только наиболее общие описания классов. Более конкретная информация содержится в самом объекте исключения. Классы исключений необходимы для того, чтобы сортировать возникающие ошибки по типам, и на основе этой информации обрабатывать их различным образом.&lt;br /&gt;
&lt;br /&gt;
Например, в описанном выше случае, наиболее подходящим классом ошибки будет &amp;lt;tt&amp;gt;ERangeError&amp;lt;/tt&amp;gt;. Соответственно, код генерации ошибки можно написать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
throw ERangeError.create(&amp;quot;индекс должен быть в диапазоне от 5 до 10&amp;quot;);&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;'''catch'''&amp;lt;/tt&amp;gt;, следом за которым, в круглых скобках, идет описание переменной исключения, а затем, собственно, блок обработчика. Например, так мог бы выглядеть код вызова вышеописанной функции &amp;lt;tt&amp;gt;Process()&amp;lt;/tt&amp;gt; и обработки возникающего исключения, если бы оно имело место:&lt;br /&gt;
&amp;lt;source lang=kpp&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
    Process(/*выражение задающее индекс*/);&lt;br /&gt;
    /* другой код */&lt;br /&gt;
} catch (e) {&lt;br /&gt;
    print(&amp;quot;Ошибка обработки индекса. #{e.name}: #{e.description}\n&amp;quot;);&lt;br /&gt;
    /* код обработки исключения */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для того чтобы сослаться на объект исключения используется переменная ''e''. Все системные классы исключений имеют свойства &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; и &amp;lt;tt&amp;gt;description&amp;lt;/tt&amp;gt;. Первое содержит имя исключения, а второе — описание ошибки. &lt;br /&gt;
&lt;br /&gt;
В зависимости от класса исключения могут добавляться дополнительные поля, более точно характеризующие ошибку. Для того чтобы можно было классифицировать объект исключения по его классу (пардон за каламбур), применяется расширенная форма конструкции перехвата:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=kpp&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
    /* защищаемый код */&lt;br /&gt;
} catch (/*класс 1*/ /*имя объекта 1*/) {&lt;br /&gt;
    /* код обработки исключения 1 */&lt;br /&gt;
} catch (/*класс 2*/ /*имя объекта 2*/) {&lt;br /&gt;
    /* код обработки исключения 2 */&lt;br /&gt;
...&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=kpp&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
    /* защищаемый код */&lt;br /&gt;
} catch (EAgain e) {&lt;br /&gt;
    /* запрос у пользователя на повторение операции */&lt;br /&gt;
} catch (ERangeError e) {&lt;br /&gt;
    /* отображение ошибки */&lt;br /&gt;
} catch (e) {&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;'''[[Основные синтаксические конструкции#Оператор множественного выбора (switch)|switch]]'''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Примечание 1:''' следует помнить, что правильность разбора исключений по классам, зависит от очередности расположения блоков перехватчиков в конструкции. При перехвате исключения выбор обработчика происходит по принципу первого совпадения, при котором проверяется, имеет ли объект исключения в своей иерархии класс, указанный в перехватчике. Если скажем, перехватчик &amp;lt;tt&amp;gt;'''catch''' (e)&amp;lt;/tt&amp;gt; будет указан первым, то он и будет собирать все исключения, поскольку он сработает на любой класс объекта исключения. Вообще, нужно стараться располагать перехватчики по убыванию степени абстракции — от пользовательских классов до системных и далее, до общего перехватчика.&lt;br /&gt;
&lt;br /&gt;
== Ловить или не ловить? ==&lt;br /&gt;
&lt;br /&gt;
Блоки перехвата исключений должны вставляться только в тех местах, где вы точно знаете, как надо поступить при возникновении исключения. Если такой уверенности нет — смело пропускайте исключение &amp;quot;мимо ушей&amp;quot;. Рано или поздно оно будет словлено там, где программа располагает бо́льшими сведениями относительно дальнейшей модели поведения. &lt;br /&gt;
&lt;br /&gt;
То есть, не стоит ловить исключение только потому что это можно сделать. Смысл всей технологии в том, что ошибки обрабатываются в тех местах, где их можно исправить. &amp;lt;!--Приведем парочку примеров разных ситуаций, иллюстирующих проблему. Допустим, мы пишем библиотечный код работы с сетевыми соединениями, который представляет собой надстройку над сокетами. В процессе чтения из сокеты мы можем столкнуться с ошибкой чтения.--&amp;gt;&lt;br /&gt;
== Исключения и работа с ресурсами ==&lt;br /&gt;
&lt;br /&gt;
Основная проблема при работе со внешними ресурсами заключается в том, что их надо освобождать. Конечно, в нашем случае существует сборщик мусора, который рано или поздно обнаружит &amp;quot;ничейный&amp;quot; объект и инициирует процедуру его удаления. При этом, грамотно написанный unmanaged объект должен произвести все необходимые операции по освобождению ассоциированного с ним ресурса (файла, сетевого соединения, графической сущности и т. д.).&lt;br /&gt;
&lt;br /&gt;
Однако, может пройти длительное время, прежде чем сборщик мусора &amp;quot;спохватится&amp;quot; и начнет свою работу. В случае небольших программ и того хуже — он может быть вызван всего раз — при завершении работы программы. Таким образом, если программа представляет собой например скрипт, создающий на экране некоторые графические сущности или объекты виртуального пространства, то весь этот &amp;quot;мусор&amp;quot; будет маячить перед глазами до того момента, пока программист не озаботится его удалением. &lt;br /&gt;
&lt;br /&gt;
Разумеется, грамотно написанная программа должна освобождать ресурсы как можно быстрее (не путать с обычными объектами). Обычно это осуществляется вызовом специального unmanaged метода, который и производит все необходимые манипуляции на низком уровне. Тогда код работы с ресурсом может выглядеть как-то так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var resource = MyResource.open(&amp;quot;some initial data&amp;quot;); // создаем ресурс&lt;br /&gt;
resource.bla(bla);                                   // работаем с ресурсом&lt;br /&gt;
foo(resource); &lt;br /&gt;
//...                                                  &lt;br /&gt;
resource.release();                                  // освобождаем ресурс&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В приведенном выше примере, метод &amp;lt;tt&amp;gt;release()&amp;lt;/tt&amp;gt; является финализатором, который освобождает ресурс. Логическая ошибка такого кода в том, что он будет корректно рабоать только в случае нормальной работы программы. В случае если код работы с ресурсом возбудит исключение, управление будет передано &amp;quot;наверх&amp;quot; минуя оставшуюся часть кода, в том числе и оператор финализации. В результате, ассоциированные с этим блоком кода ресурсы не будут освобождены тогда, когда этого хотелось разработчику.&lt;br /&gt;
&lt;br /&gt;
В принципе, можно попробовать схитрить и обернуть данный код в &amp;lt;tt&amp;gt;'''try'''&amp;lt;/tt&amp;gt; блок, а в блоке перехвата исключений проводить принудительную финализацию ресурса. Тогда код будет выглядеть как-то так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var resource = MyResource.open(&amp;quot;some initial data&amp;quot;);   // создаем ресурс&lt;br /&gt;
try {&lt;br /&gt;
  resource.bla(bla);                                   // работаем с ресурсом&lt;br /&gt;
  foo(resource);                                       &lt;br /&gt;
  //...&lt;br /&gt;
  resource.release();                                  // освобождаем ресурс&lt;br /&gt;
} catch (Exception e) {&lt;br /&gt;
  resource.release();                                  // освобождаем ресурс&lt;br /&gt;
  throw e;                                             // вторично выбрасываем исключение&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
С функциональной точки зрения этот код корректен. Ресурс финализируется в любом случае, вне зависимости от того, каким образом управление покинуло защищаемый блок кода. Однако с точки зрения удобства использования и &amp;quot;прозрачности&amp;quot; такой код не очень хорош. Тело программы перегружается повторяющимися конструкциями, код становится менее читаем; не говорим уже о том, что можно банально забыть вписать строку финализации в обработчик исключения (или забыть изменить ее при смене процедуры финализации). В общем и целом, такой подход производит больше проблем чем решает.&lt;br /&gt;
&lt;br /&gt;
Для того чтобы сказать компилятору, что некоторый код необходимо выполнить в любом случае, независимо от того что произошло выше, необходимо использовать ключевое слово &amp;lt;tt&amp;gt;'''ensure'''&amp;lt;/tt&amp;gt;. Тогда вышеприведенный код примет следующий вид:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var resource = MyResource.open(&amp;quot;some initial data&amp;quot;);   // создаем ресурс&lt;br /&gt;
try {&lt;br /&gt;
  resource.bla(bla);                                   // работаем с ресурсом&lt;br /&gt;
  foo(resource);                 &lt;br /&gt;
  // ...&lt;br /&gt;
} ensure {&lt;br /&gt;
  resource.release();                                  // освобождаем ресурс&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание, что код финализации записан всего один раз, отдельно от основного кода. Никаких промежуточных объектов исключения и прочей &amp;quot;шелухи&amp;quot; не наблюдается. Всю работу по организации потока управления компилятор берет на себя. От нас требуется только корректно записать код работы с объектом.&lt;br /&gt;
&lt;br /&gt;
Конструкция работает следующим образом: сначала вызвается инициализатор ресурса, то есть первая строка. Затем управление передается в защищаемый блок. Если все прошло гладко и исключений выброшено не было, то после защищаемого блока вызывается &amp;lt;tt&amp;gt;'''ensure'''&amp;lt;/tt&amp;gt; блок а затем управление передается дальше по коду.&lt;br /&gt;
&lt;br /&gt;
Если же где то в защищаемом коде было выброшено исключение, управление &amp;lt;em&amp;gt;сперва&amp;lt;/em&amp;gt; передается в &amp;lt;tt&amp;gt;'''ensure'''&amp;lt;/tt&amp;gt; блок, а потом выброшенное исключение передается &amp;quot;наверх&amp;quot;; то есть управление будет переданно ближайшему &amp;lt;tt&amp;gt;'''catch'''&amp;lt;/tt&amp;gt; блоку, способному обработать данный класс исключений. Самое главное заключается в том, что освобождение ресурса гарантируется в любом случае.&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%9E%D0%B1%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0_%D0%B8%D1%81%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B9</id>
		<title>Обработка исключений</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%9E%D0%B1%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0_%D0%B8%D1%81%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B9"/>
				<updated>2009-10-28T04:54:29Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* Исключения и работа с ресурсами */&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;
Все вышеперечисленные события так или иначе могут произойти в ходе работы программы, однако, с точностью предсказать их практически невозможно, можно только оценить вероятность. Хорошая программа так и делает: в тех местах, где могут потенциально произойти исключительные ситуации, вставляется код, проверяющий состояние и производящий некоторые действия по &amp;quot;ликвидации последствий&amp;quot;. Например, в случае ошибки связи, программа может попытаться установить соединение заново, в то время как при ошибке внезапного конца файла, остается только уведомить об этом пользователя, показав соответствующее сообщение об ошибке.&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;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
    /* try-блок (основное тело) */&lt;br /&gt;
} catch (/* переменная для объекта исключения 1 */) {&lt;br /&gt;
    /* код перехватчика 1 */&lt;br /&gt;
} catch (/* переменная для объекта исключения 2 */) {&lt;br /&gt;
    /* код перехватчика 2 */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ключевое слово &amp;lt;tt&amp;gt;'''try'''&amp;lt;/tt&amp;gt; объявляет начало защищенного блока. Затем, идет основное тело или try-блок, в котором содержатся конструкции, соответствующие нормальной работе. В примере с файлом, здесь будет находиться код чтения содержимого файла и, возможно, его обработки. Если в ходе выполнения этого блока, возникнет исключительная ситуация, то управление будет передано одному из блоков обработки, соответствующему типу возникшего исключения (об этом чуть позже). В круглых скобках указывается имя переменной, которой будет назначен ''объект исключения'' — объект некоторого класса, который был &amp;quot;выброшен&amp;quot; из кода в качестве исключения.&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;
Код, который первым обнаруживает исключительную ситуацию (то есть, стоит у ее истоков) и желающий сообщить о ней &amp;quot;наверх&amp;quot;, должен создать объект исключения и &amp;quot;выбросить&amp;quot; его. Создается объект так же, как и любой другой объект в языке К++: либо с помощью оператора &amp;lt;tt&amp;gt;'''new'''&amp;lt;/tt&amp;gt;, либо с помощью [[Классы и объекты#Конструкторы|конструктора]] (если он предусмотрен). &amp;quot;Выбрасывание&amp;quot; объекта осуществляется с помощью специального оператора &amp;lt;tt&amp;gt;'''throw'''&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;
function Process(const int idx) {&lt;br /&gt;
    if (! idx in 5 .. 10)&lt;br /&gt;
        throw &amp;quot;индекс должен быть в диапазоне от 5 до 10&amp;quot;;&lt;br /&gt;
    /* нормальный код обработки */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В первой строке тела функции, проверяется условие, необходимое функции для работы. Если условие не выполняется, то производится генерация исключения, причем в качестве объекта исключения выступает объект строки. &lt;br /&gt;
&lt;br /&gt;
На практике применяются специальные классы распространенных исключений, которые объявлены в [[Стандартная библиотека Gide|стандартной библиотеке]]. Таким образом, все языки использующие стандартную библиотеку и умеющие работать с исключениями, смогут успешно взаимодействовать с помощью этого механизма.&lt;br /&gt;
&lt;br /&gt;
Приведем некоторые из наиболее распространенных классов исключений и поясним их назначение:&lt;br /&gt;
&lt;br /&gt;
::{| width=60%&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EInvalidCall&amp;lt;/tt&amp;gt; || неверный вызов (входные данные неверны)&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EFailed&amp;lt;/tt&amp;gt; || операция не удалась (и все тут)&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EAagain&amp;lt;/tt&amp;gt; || по тем или иным причинам требуется повтор операции&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EDenied &amp;lt;/tt&amp;gt; || действие запрещено!&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;ECancelled &amp;lt;/tt&amp;gt; || операция была отменена (например пользователем)&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EAlready&amp;lt;/tt&amp;gt; || операция уже была выполнена&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;ERangeError&amp;lt;/tt&amp;gt; || ошибка диапазона (выход значения за допустимые границы)&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EDivisionByZero&amp;lt;/tt&amp;gt; || арифметическая ошибка деления на ноль&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;ETimeout  &amp;lt;/tt&amp;gt; || истекло время ожидания чего-либо&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EStreamError&amp;lt;/tt&amp;gt; || ошибка [[потока]]&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;ERegexpError&amp;lt;/tt&amp;gt; || ошибка при разборе [[регулярного выражения]]&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EAbstractError&amp;lt;/tt&amp;gt; || попытка вызова [[Классы и объекты#Методы|абстрактного метода]]&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Здесь приведены только наиболее общие описания классов. Более конкретная информация содержится в самом объекте исключения. Классы исключений необходимы для того, чтобы сортировать возникающие ошибки по типам, и на основе этой информации обрабатывать их различным образом.&lt;br /&gt;
&lt;br /&gt;
Например, в описанном выше случае, наиболее подходящим классом ошибки будет &amp;lt;tt&amp;gt;ERangeError&amp;lt;/tt&amp;gt;. Соответственно, код генерации ошибки можно написать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
throw ERangeError.create(&amp;quot;индекс должен быть в диапазоне от 5 до 10&amp;quot;);&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;'''catch'''&amp;lt;/tt&amp;gt;, следом за которым, в круглых скобках, идет описание переменной исключения, а затем, собственно, блок обработчика. Например, так мог бы выглядеть код вызова вышеописанной функции &amp;lt;tt&amp;gt;Process()&amp;lt;/tt&amp;gt; и обработки возникающего исключения, если бы оно имело место:&lt;br /&gt;
&amp;lt;source lang=kpp&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
    Process(/*выражение задающее индекс*/);&lt;br /&gt;
    /* другой код */&lt;br /&gt;
} catch (e) {&lt;br /&gt;
    print(&amp;quot;Ошибка обработки индекса. #{e.name}: #{e.description}\n&amp;quot;);&lt;br /&gt;
    /* код обработки исключения */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для того чтобы сослаться на объект исключения используется переменная ''e''. Все системные классы исключений имеют свойства &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; и &amp;lt;tt&amp;gt;description&amp;lt;/tt&amp;gt;. Первое содержит имя исключения, а второе — описание ошибки. &lt;br /&gt;
&lt;br /&gt;
В зависимости от класса исключения могут добавляться дополнительные поля, более точно характеризующие ошибку. Для того чтобы можно было классифицировать объект исключения по его классу (пардон за каламбур), применяется расширенная форма конструкции перехвата:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=kpp&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
    /* защищаемый код */&lt;br /&gt;
} catch (/*класс 1*/ /*имя объекта 1*/) {&lt;br /&gt;
    /* код обработки исключения 1 */&lt;br /&gt;
} catch (/*класс 2*/ /*имя объекта 2*/) {&lt;br /&gt;
    /* код обработки исключения 2 */&lt;br /&gt;
...&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=kpp&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
    /* защищаемый код */&lt;br /&gt;
} catch (EAgain e) {&lt;br /&gt;
    /* запрос у пользователя на повторение операции */&lt;br /&gt;
} catch (ERangeError e) {&lt;br /&gt;
    /* отображение ошибки */&lt;br /&gt;
} catch (e) {&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;'''[[Основные синтаксические конструкции#Оператор множественного выбора (switch)|switch]]'''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Примечание 1:''' следует помнить, что правильность разбора исключений по классам, зависит от очередности расположения блоков перехватчиков в конструкции. При перехвате исключения выбор обработчика происходит по принципу первого совпадения, при котором проверяется, имеет ли объект исключения в своей иерархии класс, указанный в перехватчике. Если скажем, перехватчик &amp;lt;tt&amp;gt;'''catch''' (e)&amp;lt;/tt&amp;gt; будет указан первым, то он и будет собирать все исключения, поскольку он сработает на любой класс объекта исключения. Вообще, нужно стараться располагать перехватчики по убыванию степени абстракции — от пользовательских классов до системных и далее, до общего перехватчика.&lt;br /&gt;
&lt;br /&gt;
== Исключения и работа с ресурсами ==&lt;br /&gt;
&lt;br /&gt;
Основная проблема при работе со внешними ресурсами заключается в том, что их надо освобождать. Конечно, в нашем случае существует сборщик мусора, который рано или поздно обнаружит &amp;quot;ничейный&amp;quot; объект и инициирует процедуру его удаления. При этом, грамотно написанный unmanaged объект должен произвести все необходимые операции по освобождению ассоциированного с ним ресурса (файла, сетевого соединения, графической сущности и т. д.).&lt;br /&gt;
&lt;br /&gt;
Однако, может пройти длительное время, прежде чем сборщик мусора &amp;quot;спохватится&amp;quot; и начнет свою работу. В случае небольших программ и того хуже — он может быть вызван всего раз — при завершении работы программы. Таким образом, если программа представляет собой например скрипт, создающий на экране некоторые графические сущности или объекты виртуального пространства, то весь этот &amp;quot;мусор&amp;quot; будет маячить перед глазами до того момента, пока программист не озаботится его удалением. &lt;br /&gt;
&lt;br /&gt;
Разумеется, грамотно написанная программа должна освобождать ресурсы как можно быстрее (не путать с обычными объектами). Обычно это осуществляется вызовом специального unmanaged метода, который и производит все необходимые манипуляции на низком уровне. Тогда код работы с ресурсом может выглядеть как-то так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var resource = MyResource.open(&amp;quot;some initial data&amp;quot;); // создаем ресурс&lt;br /&gt;
resource.bla(bla);                                   // работаем с ресурсом&lt;br /&gt;
foo(resource); &lt;br /&gt;
//...                                                  &lt;br /&gt;
resource.release();                                  // освобождаем ресурс&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В приведенном выше примере, метод &amp;lt;tt&amp;gt;release()&amp;lt;/tt&amp;gt; является финализатором, который освобождает ресурс. Логическая ошибка такого кода в том, что он будет корректно рабоать только в случае нормальной работы программы. В случае если код работы с ресурсом возбудит исключение, управление будет передано &amp;quot;наверх&amp;quot; минуя оставшуюся часть кода, в том числе и оператор финализации. В результате, ассоциированные с этим блоком кода ресурсы не будут освобождены тогда, когда этого хотелось разработчику.&lt;br /&gt;
&lt;br /&gt;
В принципе, можно попробовать схитрить и обернуть данный код в &amp;lt;tt&amp;gt;'''try'''&amp;lt;/tt&amp;gt; блок, а в блоке перехвата исключений проводить принудительную финализацию ресурса. Тогда код будет выглядеть как-то так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var resource = MyResource.open(&amp;quot;some initial data&amp;quot;);   // создаем ресурс&lt;br /&gt;
try {&lt;br /&gt;
  resource.bla(bla);                                   // работаем с ресурсом&lt;br /&gt;
  foo(resource);                                       &lt;br /&gt;
  //...&lt;br /&gt;
  resource.release();                                  // освобождаем ресурс&lt;br /&gt;
} catch (Exception e) {&lt;br /&gt;
  resource.release();                                  // освобождаем ресурс&lt;br /&gt;
  throw e;                                             // вторично выбрасываем исключение&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
С функциональной точки зрения этот код корректен. Ресурс финализируется в любом случае, вне зависимости от того, каким образом управление покинуло защищаемый блок кода. Однако с точки зрения удобства использования и &amp;quot;прозрачности&amp;quot; такой код не очень хорош. Тело программы перегружается повторяющимися конструкциями, код становится менее читаем; не говорим уже о том, что можно банально забыть вписать строку финализации в обработчик исключения (или забыть изменить ее при смене процедуры финализации). В общем и целом, такой подход производит больше проблем чем решает.&lt;br /&gt;
&lt;br /&gt;
Для того чтобы сказать компилятору, что некоторый код необходимо выполнить в любом случае, независимо от того что произошло выше, необходимо использовать ключевое слово &amp;lt;tt&amp;gt;'''ensure'''&amp;lt;/tt&amp;gt;. Тогда вышеприведенный код примет следующий вид:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var resource = MyResource.open(&amp;quot;some initial data&amp;quot;);   // создаем ресурс&lt;br /&gt;
try {&lt;br /&gt;
  resource.bla(bla);                                   // работаем с ресурсом&lt;br /&gt;
  foo(resource);                 &lt;br /&gt;
  // ...&lt;br /&gt;
} ensure {&lt;br /&gt;
  resource.release();                                  // освобождаем ресурс&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание, что код финализации записан всего один раз, отдельно от основного кода. Никаких промежуточных объектов исключения и прочей &amp;quot;шелухи&amp;quot; не наблюдается. Всю работу по организации потока управления компилятор берет на себя. От нас требуется только корректно записать код работы с объектом.&lt;br /&gt;
&lt;br /&gt;
Конструкция работает следующим образом: сначала вызвается инициализатор ресурса, то есть первая строка. Затем управление передается в защищаемый блок. Если все прошло гладко и исключений выброшено не было, то после защищаемого блока вызывается &amp;lt;tt&amp;gt;'''ensure'''&amp;lt;/tt&amp;gt; блок а затем управление передается дальше по коду.&lt;br /&gt;
&lt;br /&gt;
Если же где то в защищаемом коде было выброшено исключение, управление &amp;lt;em&amp;gt;сперва&amp;lt;/em&amp;gt; передается в &amp;lt;tt&amp;gt;'''ensure'''&amp;lt;/tt&amp;gt; блок, а потом выброшенное исключение передается &amp;quot;наверх&amp;quot;; то есть управление будет переданно ближайшему &amp;lt;tt&amp;gt;'''catch'''&amp;lt;/tt&amp;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;
&amp;lt;!--Приведем парочку примеров разных ситуаций, иллюстирующих проблему. Допустим, мы пишем библиотечный код работы с сетевыми соединениями, который представляет собой надстройку над сокетами. В процессе чтения из сокеты мы можем столкнуться с ошибкой чтения.--&amp;gt;&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%9E%D0%B1%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0_%D0%B8%D1%81%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B9</id>
		<title>Обработка исключений</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%9E%D0%B1%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0_%D0%B8%D1%81%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B9"/>
				<updated>2009-10-28T04:45:44Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* Ловить или не ловить? */&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;
Все вышеперечисленные события так или иначе могут произойти в ходе работы программы, однако, с точностью предсказать их практически невозможно, можно только оценить вероятность. Хорошая программа так и делает: в тех местах, где могут потенциально произойти исключительные ситуации, вставляется код, проверяющий состояние и производящий некоторые действия по &amp;quot;ликвидации последствий&amp;quot;. Например, в случае ошибки связи, программа может попытаться установить соединение заново, в то время как при ошибке внезапного конца файла, остается только уведомить об этом пользователя, показав соответствующее сообщение об ошибке.&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;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
    /* try-блок (основное тело) */&lt;br /&gt;
} catch (/* переменная для объекта исключения 1 */) {&lt;br /&gt;
    /* код перехватчика 1 */&lt;br /&gt;
} catch (/* переменная для объекта исключения 2 */) {&lt;br /&gt;
    /* код перехватчика 2 */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ключевое слово &amp;lt;tt&amp;gt;'''try'''&amp;lt;/tt&amp;gt; объявляет начало защищенного блока. Затем, идет основное тело или try-блок, в котором содержатся конструкции, соответствующие нормальной работе. В примере с файлом, здесь будет находиться код чтения содержимого файла и, возможно, его обработки. Если в ходе выполнения этого блока, возникнет исключительная ситуация, то управление будет передано одному из блоков обработки, соответствующему типу возникшего исключения (об этом чуть позже). В круглых скобках указывается имя переменной, которой будет назначен ''объект исключения'' — объект некоторого класса, который был &amp;quot;выброшен&amp;quot; из кода в качестве исключения.&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;
Код, который первым обнаруживает исключительную ситуацию (то есть, стоит у ее истоков) и желающий сообщить о ней &amp;quot;наверх&amp;quot;, должен создать объект исключения и &amp;quot;выбросить&amp;quot; его. Создается объект так же, как и любой другой объект в языке К++: либо с помощью оператора &amp;lt;tt&amp;gt;'''new'''&amp;lt;/tt&amp;gt;, либо с помощью [[Классы и объекты#Конструкторы|конструктора]] (если он предусмотрен). &amp;quot;Выбрасывание&amp;quot; объекта осуществляется с помощью специального оператора &amp;lt;tt&amp;gt;'''throw'''&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;
function Process(const int idx) {&lt;br /&gt;
    if (! idx in 5 .. 10)&lt;br /&gt;
        throw &amp;quot;индекс должен быть в диапазоне от 5 до 10&amp;quot;;&lt;br /&gt;
    /* нормальный код обработки */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В первой строке тела функции, проверяется условие, необходимое функции для работы. Если условие не выполняется, то производится генерация исключения, причем в качестве объекта исключения выступает объект строки. &lt;br /&gt;
&lt;br /&gt;
На практике применяются специальные классы распространенных исключений, которые объявлены в [[Стандартная библиотека Gide|стандартной библиотеке]]. Таким образом, все языки использующие стандартную библиотеку и умеющие работать с исключениями, смогут успешно взаимодействовать с помощью этого механизма.&lt;br /&gt;
&lt;br /&gt;
Приведем некоторые из наиболее распространенных классов исключений и поясним их назначение:&lt;br /&gt;
&lt;br /&gt;
::{| width=60%&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EInvalidCall&amp;lt;/tt&amp;gt; || неверный вызов (входные данные неверны)&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EFailed&amp;lt;/tt&amp;gt; || операция не удалась (и все тут)&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EAagain&amp;lt;/tt&amp;gt; || по тем или иным причинам требуется повтор операции&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EDenied &amp;lt;/tt&amp;gt; || действие запрещено!&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;ECancelled &amp;lt;/tt&amp;gt; || операция была отменена (например пользователем)&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EAlready&amp;lt;/tt&amp;gt; || операция уже была выполнена&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;ERangeError&amp;lt;/tt&amp;gt; || ошибка диапазона (выход значения за допустимые границы)&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EDivisionByZero&amp;lt;/tt&amp;gt; || арифметическая ошибка деления на ноль&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;ETimeout  &amp;lt;/tt&amp;gt; || истекло время ожидания чего-либо&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EStreamError&amp;lt;/tt&amp;gt; || ошибка [[потока]]&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;ERegexpError&amp;lt;/tt&amp;gt; || ошибка при разборе [[регулярного выражения]]&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EAbstractError&amp;lt;/tt&amp;gt; || попытка вызова [[Классы и объекты#Методы|абстрактного метода]]&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Здесь приведены только наиболее общие описания классов. Более конкретная информация содержится в самом объекте исключения. Классы исключений необходимы для того, чтобы сортировать возникающие ошибки по типам, и на основе этой информации обрабатывать их различным образом.&lt;br /&gt;
&lt;br /&gt;
Например, в описанном выше случае, наиболее подходящим классом ошибки будет &amp;lt;tt&amp;gt;ERangeError&amp;lt;/tt&amp;gt;. Соответственно, код генерации ошибки можно написать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
throw ERangeError.create(&amp;quot;индекс должен быть в диапазоне от 5 до 10&amp;quot;);&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;'''catch'''&amp;lt;/tt&amp;gt;, следом за которым, в круглых скобках, идет описание переменной исключения, а затем, собственно, блок обработчика. Например, так мог бы выглядеть код вызова вышеописанной функции &amp;lt;tt&amp;gt;Process()&amp;lt;/tt&amp;gt; и обработки возникающего исключения, если бы оно имело место:&lt;br /&gt;
&amp;lt;source lang=kpp&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
    Process(/*выражение задающее индекс*/);&lt;br /&gt;
    /* другой код */&lt;br /&gt;
} catch (e) {&lt;br /&gt;
    print(&amp;quot;Ошибка обработки индекса. #{e.name}: #{e.description}\n&amp;quot;);&lt;br /&gt;
    /* код обработки исключения */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для того чтобы сослаться на объект исключения используется переменная ''e''. Все системные классы исключений имеют свойства &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; и &amp;lt;tt&amp;gt;description&amp;lt;/tt&amp;gt;. Первое содержит имя исключения, а второе — описание ошибки. &lt;br /&gt;
&lt;br /&gt;
В зависимости от класса исключения могут добавляться дополнительные поля, более точно характеризующие ошибку. Для того чтобы можно было классифицировать объект исключения по его классу (пардон за каламбур), применяется расширенная форма конструкции перехвата:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=kpp&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
    /* защищаемый код */&lt;br /&gt;
} catch (/*класс 1*/ /*имя объекта 1*/) {&lt;br /&gt;
    /* код обработки исключения 1 */&lt;br /&gt;
} catch (/*класс 2*/ /*имя объекта 2*/) {&lt;br /&gt;
    /* код обработки исключения 2 */&lt;br /&gt;
...&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=kpp&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
    /* защищаемый код */&lt;br /&gt;
} catch (EAgain e) {&lt;br /&gt;
    /* запрос у пользователя на повторение операции */&lt;br /&gt;
} catch (ERangeError e) {&lt;br /&gt;
    /* отображение ошибки */&lt;br /&gt;
} catch (e) {&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;'''[[Основные синтаксические конструкции#Оператор множественного выбора (switch)|switch]]'''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Примечание 1:''' следует помнить, что правильность разбора исключений по классам, зависит от очередности расположения блоков перехватчиков в конструкции. При перехвате исключения выбор обработчика происходит по принципу первого совпадения, при котором проверяется, имеет ли объект исключения в своей иерархии класс, указанный в перехватчике. Если скажем, перехватчик &amp;lt;tt&amp;gt;'''catch''' (e)&amp;lt;/tt&amp;gt; будет указан первым, то он и будет собирать все исключения, поскольку он сработает на любой класс объекта исключения. Вообще, нужно стараться располагать перехватчики по убыванию степени абстракции — от пользовательских классов до системных и далее, до общего перехватчика.&lt;br /&gt;
&lt;br /&gt;
== Исключения и работа с ресурсами ==&lt;br /&gt;
&lt;br /&gt;
Основная проблема при работе со внешними ресурсами заключается в том, что их надо освобождать. Конечно, в нашем случае существует сборщик мусора, который рано или поздно обнаружит &amp;quot;ничейный&amp;quot; объект и инициирует процедуру его удаления. При этом, грамотно написанный unmanaged объект должен произвести все необходимые операции по освобождению ассоциированного с ним ресурса (файла, сетевого соединения, графической сущности и т. д.).&lt;br /&gt;
&lt;br /&gt;
Однако, может пройти длительное время, прежде чем сборщик мусора &amp;quot;спохватится&amp;quot; и начнет свою работу. В случае небольших программ и того хуже — он может быть вызван всего раз — при завершении работы программы. Таким образом, если программа представляет собой например скрипт, создающий на экране некоторые графические сущности или объекты виртуального пространства, то весь этот &amp;quot;мусор&amp;quot; будет маячить перед глазами до того момента, пока программист не озаботится его удалением. &lt;br /&gt;
&lt;br /&gt;
Разумеется, грамотно написанная программа должна освобождать ресурсы как можно быстрее (не путать с обычными объектами). Обычно это осуществляется вызовом специального unmanaged метода, который и производит все необходимые манипуляции на низком уровне. Тогда код работы с ресурсом может выглядеть как-то так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var resource = MyResource.open(&amp;quot;some initial data&amp;quot;); // создаем ресурс&lt;br /&gt;
resource.bla(bla);                                   // работаем с ресурсом&lt;br /&gt;
foo(resource); &lt;br /&gt;
//...                                                  &lt;br /&gt;
resource.release();                                  // освобождаем ресурс&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В приведенном выше примере, метод &amp;lt;tt&amp;gt;release()&amp;lt;/tt&amp;gt; является финализатором, который освобождает ресурс. Логическая ошибка такого кода в том, что он будет корректно рабоать только в случае нормальной работы программы. В случае если код работы с ресурсом возбудит исключение, управление будет передано &amp;quot;наверх&amp;quot; минуя оставшуюся часть кода, в том числе и оператор финализации. В результате, ассоциированные с этим блоком кода ресурсы не будут освобождены тогда, когда это хотелось разработчику.&lt;br /&gt;
&lt;br /&gt;
Разумеется, можно попробовать схитрить и обернуть данный код в &amp;lt;tt&amp;gt;'''try'''&amp;lt;/tt&amp;gt; блок, а в блоке перехвата исключений проводить принудительную финализацию ресурса. Тогда код будет выглядеть как-то так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var resource = MyResource.open(&amp;quot;some initial data&amp;quot;);   // создаем ресурс&lt;br /&gt;
try {&lt;br /&gt;
  resource.bla(bla); &lt;br /&gt;
  foo(resource);                                       // работаем с ресурсом&lt;br /&gt;
  //...&lt;br /&gt;
  resource.release();                                  // освобождаем ресурс&lt;br /&gt;
} catch (Exception e) {&lt;br /&gt;
  resource.release();                                  // освобождаем ресурс&lt;br /&gt;
  throw e;                                             // вторично выбрасываем исключение&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
С функциональной точки зрения этот код корректен. Ресурс финализируется в любом случае, вне зависимости от того, каким образом управление покинуло защищаемый блок кода. Однако с точки зрения удобства использования и &amp;quot;прозрачности&amp;quot; такой код не очень хорош. Тело программы перегружается повторяющимися конструкциями, код становится менее читаем; не говорим уже о том, что можно банально забыть вписать строку финализации в обработчик исключения (или изменить ее при смене процедуры финализации). В общем и целом, такой подход производит больше проблем чем решает.&lt;br /&gt;
&lt;br /&gt;
Для того чтобы сказать компилятору, что некоторый код необходимо выполнить в любом случае, независимо от того что произошло выше, необходимо использовать ключевое слово &amp;lt;tt&amp;gt;'''ensure'''&amp;lt;/tt&amp;gt;. Тогда вышеприведенный код примет следующий вид:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var resource = MyResource.open(&amp;quot;some initial data&amp;quot;);   // создаем ресурс&lt;br /&gt;
try {&lt;br /&gt;
  resource.bla(bla);                                   // работаем с ресурсом&lt;br /&gt;
  foo(resource);                 &lt;br /&gt;
  // ...&lt;br /&gt;
} ensure {&lt;br /&gt;
  resource.release();                                  // освобождаем ресурс&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание, что код финализации записан всего один раз, отдельно от основного кода. Никаких промежуточных объектов исключения и прочей &amp;quot;шелухи&amp;quot; не наблюдается. Всю работу по организации потока управления компилятор берет на себя. От нас требуется только корректно записать код работы с объектом.&lt;br /&gt;
&lt;br /&gt;
Конструкция работает следующим образом: сначала вызвается инициализатор ресурса, то есть первая строка. Затем управление передается в защищаемый блок. Если все прошло гладко и исключений выброшено не было, то после защищаемого блока вызывается &amp;lt;tt&amp;gt;'''ensure'''&amp;lt;/tt&amp;gt; блок а затем управление передается дальше по коду.&lt;br /&gt;
&lt;br /&gt;
Если же где то в защищаемом коде было выброшено исключение, управление &amp;lt;em&amp;gt;сперва&amp;lt;/em&amp;gt; передается в &amp;lt;tt&amp;gt;'''ensure'''&amp;lt;/tt&amp;gt; блок, а потом выброшенное исключение передается &amp;quot;наверх&amp;quot;; то есть управление будет переданно ближайшему &amp;lt;tt&amp;gt;'''catch'''&amp;lt;/tt&amp;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;
&amp;lt;!--Приведем парочку примеров разных ситуаций, иллюстирующих проблему. Допустим, мы пишем библиотечный код работы с сетевыми соединениями, который представляет собой надстройку над сокетами. В процессе чтения из сокеты мы можем столкнуться с ошибкой чтения.--&amp;gt;&lt;/div&gt;</summary>
		<author><name>Korvin</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>2009-10-26T17:13:46Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* Абстрактные методы */&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;
    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;
export 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-8: В этом примере мы создаем класс &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt;, который представляет собой некоторую коробку. Мы определяем ее свойства, такие как ''материал'' и ''содержимое''.&lt;br /&gt;
&lt;br /&gt;
;11-13: Далее мы определяем класс &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;
;15-17: Мы определяем некоторую [[Функции|функцию]] для работы с нашими классами, которая будет отображать их состояние. Заметьте, что в качестве [[Функции#Аргументы|аргумента функции]] передается экземпляр класса &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt;, то есть класса-родителя. При этом мы предполагаем, что любой класс, унаследованный от базового класса, будет обладать необходимым нам интерфейсом, а именно методами получения информации о свойствах (аксессорами мы их не называем, потому что они не связаны с конкретным полем; это было бы неверно).&lt;br /&gt;
&lt;br /&gt;
;19-24: Объявляется функция &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;
В теле метода доступны все поля, методы и свойства данного класса и его предков. Например, в нижеприведенном коде, метод &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;
&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() { return F1(); }&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;
При объявлении статического метода нужно указать ключевое слово &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;
&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;'''Внимание: информация в этом разделе устарела. Необходимо обновление'''&amp;lt;/font&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;
&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;
Случается, что при проектировании интерфейсов классов, возникает желание объявить некоторый набор методов в базовом классе, однако не реализовывать их. Обычно это связано с тем, что базовый класс не располагает достаточным количеством информации или возможностей для реализации этой функции. В таких случаях прменяется спецификатор &amp;lt;tt&amp;gt;'''abstract'''&amp;lt;/tt&amp;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;. Зачастую, ошибки подобного рода обнаруживаются только во время выполнения программы.&lt;br /&gt;
&lt;br /&gt;
Наконец, объявление абстрактного метода в базовом классе, позволяет автоматически генерировать особый тип исключения: &amp;lt;tt&amp;gt;[[EAbstractError]]&amp;lt;/tt&amp;gt;. Оно возникает в случае, если была произведена попытка вызова метода объявленного абстрактным в базовом классе но не реализованом в используемом потомке. В таком случае сразу ясно, где кроется ошибка. Если бы объявления не было, то возникло бы обычное исключение о том что метод не найден. &lt;br /&gt;
&lt;br /&gt;
Примечание: Использование абстрактных методов особенно удобно при реализации [[примесей|Примеси]]. Приведем пример стандартной примеси &amp;lt;tt&amp;gt;[[Enumerable|примесь Enumerable]]&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;
/* Примесь Enumerable предоставляет классам коллекций несколько методов для итерации по элементам, &lt;br /&gt;
   выбору, поиску и возможности сортировки. &lt;br /&gt;
&lt;br /&gt;
   Класс испольщующий примесь должен объявить у себя метод each(), &lt;br /&gt;
   который вызывает переданный блок последовательно передавая ему элементы коллекции &lt;br /&gt;
&lt;br /&gt;
   Если требуется использовать методы Enumerable::max, min или алгоритм сортировки, то необходимо&lt;br /&gt;
   также реализовать соответствующий метод compare() */&lt;br /&gt;
&lt;br /&gt;
var identity_block = { |x| x; };&lt;br /&gt;
&lt;br /&gt;
class Enumerable {&lt;br /&gt;
public:&lt;br /&gt;
    abstract const function each(block b);&lt;br /&gt;
    abstract const function int compare(const x);&lt;br /&gt;
&lt;br /&gt;
    const function bool all(block b = identity_block) {&lt;br /&gt;
        var result = true;&lt;br /&gt;
        this.each() { |...|&lt;br /&gt;
            if (!b.invoke(args())) {&lt;br /&gt;
                result = false;&lt;br /&gt;
                break;&lt;br /&gt;
            }&lt;br /&gt;
        };&lt;br /&gt;
        return result;&lt;br /&gt;
    }&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;
&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;
puts(&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;
'''Примечание 2:''' Существует альтернативный синтаксис описания аксессоров и мутаторов, при котором код соответствующий им записывается прямо в определении самого свойства. Это выглядит так:&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 f = 1;&lt;br /&gt;
    property int read { f + 1; } write { |v| f = v; };&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
И аксессор и мутатор, представлены здесь в виде inline конструкций, схожих по описанию (и смыслу) с inline блоками. Аксессор возвращает значение поля ''f'', увеличенное на единицу, в то время как мутатор принимает некоторое значение ''v'' и записывает его в соответствующее поле без каких либо изменений.&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;
Как правило, расширения применяются к классам [[Стандартной библиотека 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;
&lt;br /&gt;
extend int {&lt;br /&gt;
    const function int GetFactorial() {&lt;br /&gt;
        var result = 1;&lt;br /&gt;
        for (var x = this; x &amp;gt; 1; x--)&lt;br /&gt;
            result *= x;&lt;br /&gt;
        return result;&lt;br /&gt;
    }&lt;br /&gt;
    property int factorial read GetFactorial;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
export function main() {&lt;br /&gt;
    puts(&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;
;3-11: Мы объявляем расширение класса &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;
;14: Здесь мы видим применение расширения в действии. Константа 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;puts()&amp;lt;/tt&amp;gt;, принимает в качестве параметра [[Стандартные типы данных#Строки|строку]], в то время как тип свойства определен как &amp;lt;tt&amp;gt;[[Стандартные типы данных#Целые числа|int]]&amp;lt;/tt&amp;gt;. В этом нет ничего странного, потому что класс &amp;lt;tt&amp;gt;int&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;
&amp;lt;!-- '''Примечание:''' При работе с расширениями существует одно важное ограничение. Расширять классы можно только методами и свойствами, но не полями. Это связано с внутренней организацией языка К++ и виртуальной машины. Дополнительно стоит отметить, что методы объявленные в расширении будут перекрывать соответствующие им методы класса (имеется в виду ситуация когда имена и наборы параметров полностью совпадают). Важно понимать, что такое перекрытие не является объявлением виртуального метода — происходит именно замещение старого метода новым. --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Смотри также ==&lt;/div&gt;</summary>
		<author><name>Korvin</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>2009-10-26T17:12:48Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* Абстрактные методы */&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;
    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;
export 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-8: В этом примере мы создаем класс &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt;, который представляет собой некоторую коробку. Мы определяем ее свойства, такие как ''материал'' и ''содержимое''.&lt;br /&gt;
&lt;br /&gt;
;11-13: Далее мы определяем класс &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;
;15-17: Мы определяем некоторую [[Функции|функцию]] для работы с нашими классами, которая будет отображать их состояние. Заметьте, что в качестве [[Функции#Аргументы|аргумента функции]] передается экземпляр класса &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt;, то есть класса-родителя. При этом мы предполагаем, что любой класс, унаследованный от базового класса, будет обладать необходимым нам интерфейсом, а именно методами получения информации о свойствах (аксессорами мы их не называем, потому что они не связаны с конкретным полем; это было бы неверно).&lt;br /&gt;
&lt;br /&gt;
;19-24: Объявляется функция &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;
В теле метода доступны все поля, методы и свойства данного класса и его предков. Например, в нижеприведенном коде, метод &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;
&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() { return F1(); }&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;
При объявлении статического метода нужно указать ключевое слово &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;
&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;'''Внимание: информация в этом разделе устарела. Необходимо обновление'''&amp;lt;/font&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;
&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;
Случается, что при проектировании интерфейсов классов, возникает желание объявить некоторый набор методов в базовом классе, однако не реализовывать их. Обычно это связано с тем, что базовый класс не располагает достаточным количеством информации или возможностей для реализации этой функции. В таких случаях прменяется спецификатор &amp;lt;tt&amp;gt;'''abstract'''&amp;lt;/tt&amp;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;. Зачастую, ошибки подобного рода обнаруживаются только во время выполнения программы.&lt;br /&gt;
&lt;br /&gt;
Наконец, объявление абстрактного метода в базовом классе, позволяет автоматически генерировать особый тип исключения: &amp;lt;tt&amp;gt;[[EAbstractError]]&amp;lt;/tt&amp;gt;. Оно возникает в случае, если была произведена попытка вызова метода объявленного абстрактным в базовом классе но не реализованом в используемом потомке. В таком случае сразу ясно, где кроется ошибка. Если бы объявления не было, то возникло бы обычное исключение о том что метод не найден. &lt;br /&gt;
&lt;br /&gt;
Примечание: Использование абстрактных методов особенно удобно при реализации [[примесей|Примеси]]. Приведем пример стандартной примеси &amp;lt;tt&amp;gt;[[Enumerable|примесь Enumerable]]&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;
/* Примесь Enumerable предоставляет классам коллекций несколько методов для итерации по элементам, &lt;br /&gt;
   выбору, поиску и возможности сортировки. &lt;br /&gt;
&lt;br /&gt;
   Класс испольщующий примесь должен объявить у себя метод each(), &lt;br /&gt;
   который вызывает переданный блок последовательно передавая ему элементы коллекции &lt;br /&gt;
&lt;br /&gt;
   Если требуется использовать методы Enumerable::max, min или алгоритм сортировки, то необходимо&lt;br /&gt;
   также реализовать соответствующий метод compare() */&lt;br /&gt;
&lt;br /&gt;
var identity_block = { |x| x; };&lt;br /&gt;
&lt;br /&gt;
class Enumerable {&lt;br /&gt;
public:&lt;br /&gt;
    abstract const function each(block b);&lt;br /&gt;
    abstract const function int compare(const x);&lt;br /&gt;
&lt;br /&gt;
    const function bool all(block b = identity_block) {&lt;br /&gt;
        var result = true;&lt;br /&gt;
        this.each() { |...|&lt;br /&gt;
            if (!b.invoke(args())) {&lt;br /&gt;
                result = false;&lt;br /&gt;
                break;&lt;br /&gt;
            }&lt;br /&gt;
        };&lt;br /&gt;
        return result;&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    // Другие методы примеси&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&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;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;
puts(&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;
'''Примечание 2:''' Существует альтернативный синтаксис описания аксессоров и мутаторов, при котором код соответствующий им записывается прямо в определении самого свойства. Это выглядит так:&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 f = 1;&lt;br /&gt;
    property int read { f + 1; } write { |v| f = v; };&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
И аксессор и мутатор, представлены здесь в виде inline конструкций, схожих по описанию (и смыслу) с inline блоками. Аксессор возвращает значение поля ''f'', увеличенное на единицу, в то время как мутатор принимает некоторое значение ''v'' и записывает его в соответствующее поле без каких либо изменений.&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;
Как правило, расширения применяются к классам [[Стандартной библиотека 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;
&lt;br /&gt;
extend int {&lt;br /&gt;
    const function int GetFactorial() {&lt;br /&gt;
        var result = 1;&lt;br /&gt;
        for (var x = this; x &amp;gt; 1; x--)&lt;br /&gt;
            result *= x;&lt;br /&gt;
        return result;&lt;br /&gt;
    }&lt;br /&gt;
    property int factorial read GetFactorial;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
export function main() {&lt;br /&gt;
    puts(&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;
;3-11: Мы объявляем расширение класса &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;
;14: Здесь мы видим применение расширения в действии. Константа 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;puts()&amp;lt;/tt&amp;gt;, принимает в качестве параметра [[Стандартные типы данных#Строки|строку]], в то время как тип свойства определен как &amp;lt;tt&amp;gt;[[Стандартные типы данных#Целые числа|int]]&amp;lt;/tt&amp;gt;. В этом нет ничего странного, потому что класс &amp;lt;tt&amp;gt;int&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;
&amp;lt;!-- '''Примечание:''' При работе с расширениями существует одно важное ограничение. Расширять классы можно только методами и свойствами, но не полями. Это связано с внутренней организацией языка К++ и виртуальной машины. Дополнительно стоит отметить, что методы объявленные в расширении будут перекрывать соответствующие им методы класса (имеется в виду ситуация когда имена и наборы параметров полностью совпадают). Важно понимать, что такое перекрытие не является объявлением виртуального метода — происходит именно замещение старого метода новым. --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Смотри также ==&lt;/div&gt;</summary>
		<author><name>Korvin</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>2009-10-26T11:40:47Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* Абстрактные методы */&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;
    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;
export 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-8: В этом примере мы создаем класс &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt;, который представляет собой некоторую коробку. Мы определяем ее свойства, такие как ''материал'' и ''содержимое''.&lt;br /&gt;
&lt;br /&gt;
;11-13: Далее мы определяем класс &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;
;15-17: Мы определяем некоторую [[Функции|функцию]] для работы с нашими классами, которая будет отображать их состояние. Заметьте, что в качестве [[Функции#Аргументы|аргумента функции]] передается экземпляр класса &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt;, то есть класса-родителя. При этом мы предполагаем, что любой класс, унаследованный от базового класса, будет обладать необходимым нам интерфейсом, а именно методами получения информации о свойствах (аксессорами мы их не называем, потому что они не связаны с конкретным полем; это было бы неверно).&lt;br /&gt;
&lt;br /&gt;
;19-24: Объявляется функция &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;
В теле метода доступны все поля, методы и свойства данного класса и его предков. Например, в нижеприведенном коде, метод &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;
&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() { return F1(); }&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;
При объявлении статического метода нужно указать ключевое слово &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;
&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;'''Внимание: информация в этом разделе устарела. Необходимо обновление'''&amp;lt;/font&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;
&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;
Случается, что при проектировании интерфейсов классов, возникает желание объявить некоторый набор методов в базовом классе, однако не реализовывать их. Обычно это связано с тем, что базовый класс не располагает достаточным количеством информации или возможностей для реализации этой функции. В таких случаях прменяется спецификатор &amp;lt;tt&amp;gt;'''abstract'''&amp;lt;/tt&amp;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;. Зачастую, ошибки подобного рода обнаруживаются только во время выполнения программы.&lt;br /&gt;
&lt;br /&gt;
Наконец, объявление абстрактного метода в базовом классе, позволяет автоматически генерировать особый тип исключения: &amp;lt;tt&amp;gt;[[EAbstractError]]&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;
* &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;
puts(&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;
'''Примечание 2:''' Существует альтернативный синтаксис описания аксессоров и мутаторов, при котором код соответствующий им записывается прямо в определении самого свойства. Это выглядит так:&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 f = 1;&lt;br /&gt;
    property int read { f + 1; } write { |v| f = v; };&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
И аксессор и мутатор, представлены здесь в виде inline конструкций, схожих по описанию (и смыслу) с inline блоками. Аксессор возвращает значение поля ''f'', увеличенное на единицу, в то время как мутатор принимает некоторое значение ''v'' и записывает его в соответствующее поле без каких либо изменений.&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;
Как правило, расширения применяются к классам [[Стандартной библиотека 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;
&lt;br /&gt;
extend int {&lt;br /&gt;
    const function int GetFactorial() {&lt;br /&gt;
        var result = 1;&lt;br /&gt;
        for (var x = this; x &amp;gt; 1; x--)&lt;br /&gt;
            result *= x;&lt;br /&gt;
        return result;&lt;br /&gt;
    }&lt;br /&gt;
    property int factorial read GetFactorial;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
export function main() {&lt;br /&gt;
    puts(&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;
;3-11: Мы объявляем расширение класса &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;
;14: Здесь мы видим применение расширения в действии. Константа 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;puts()&amp;lt;/tt&amp;gt;, принимает в качестве параметра [[Стандартные типы данных#Строки|строку]], в то время как тип свойства определен как &amp;lt;tt&amp;gt;[[Стандартные типы данных#Целые числа|int]]&amp;lt;/tt&amp;gt;. В этом нет ничего странного, потому что класс &amp;lt;tt&amp;gt;int&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;
&amp;lt;!-- '''Примечание:''' При работе с расширениями существует одно важное ограничение. Расширять классы можно только методами и свойствами, но не полями. Это связано с внутренней организацией языка К++ и виртуальной машины. Дополнительно стоит отметить, что методы объявленные в расширении будут перекрывать соответствующие им методы класса (имеется в виду ситуация когда имена и наборы параметров полностью совпадают). Важно понимать, что такое перекрытие не является объявлением виртуального метода — происходит именно замещение старого метода новым. --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Смотри также ==&lt;/div&gt;</summary>
		<author><name>Korvin</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>2009-10-26T11:39:53Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: Абстрактные методы&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;
    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;
export 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-8: В этом примере мы создаем класс &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt;, который представляет собой некоторую коробку. Мы определяем ее свойства, такие как ''материал'' и ''содержимое''.&lt;br /&gt;
&lt;br /&gt;
;11-13: Далее мы определяем класс &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;
;15-17: Мы определяем некоторую [[Функции|функцию]] для работы с нашими классами, которая будет отображать их состояние. Заметьте, что в качестве [[Функции#Аргументы|аргумента функции]] передается экземпляр класса &amp;lt;tt&amp;gt;Box&amp;lt;/tt&amp;gt;, то есть класса-родителя. При этом мы предполагаем, что любой класс, унаследованный от базового класса, будет обладать необходимым нам интерфейсом, а именно методами получения информации о свойствах (аксессорами мы их не называем, потому что они не связаны с конкретным полем; это было бы неверно).&lt;br /&gt;
&lt;br /&gt;
;19-24: Объявляется функция &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;
В теле метода доступны все поля, методы и свойства данного класса и его предков. Например, в нижеприведенном коде, метод &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;
&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() { return F1(); }&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;
При объявлении статического метода нужно указать ключевое слово &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;
&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;'''Внимание: информация в этом разделе устарела. Необходимо обновление'''&amp;lt;/font&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;
&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;
Случается, что при проектировании интерфейсов классов, возникает желание объявить некоторый набор методов в базовом классе, однако не реализовывать их. Обычно это связано с тем, что базовый класс не располагает достаточным количеством информации или возможностей для реализации этой функции. В таких случаях прменяется спецификатор &amp;lt;tt&amp;gt;'''abstract'''&amp;lt;/tt&amp;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;. Зачастую, ошибки подобного рода обнаруживаются только во время выполнения программы.&lt;br /&gt;
&lt;br /&gt;
Наконец, объявление абстрактного метода в базовом классе, позволяет автоматически генерировать особый тип исключения: &amp;lt;tt&amp;gt;[[EAbstractError]]&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;
* &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;
puts(&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;
'''Примечание 2:''' Существует альтернативный синтаксис описания аксессоров и мутаторов, при котором код соответствующий им записывается прямо в определении самого свойства. Это выглядит так:&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 f = 1;&lt;br /&gt;
    property int read { f + 1; } write { |v| f = v; };&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
И аксессор и мутатор, представлены здесь в виде inline конструкций, схожих по описанию (и смыслу) с inline блоками. Аксессор возвращает значение поля ''f'', увеличенное на единицу, в то время как мутатор принимает некоторое значение ''v'' и записывает его в соответствующее поле без каких либо изменений.&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;
Как правило, расширения применяются к классам [[Стандартной библиотека 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;
&lt;br /&gt;
extend int {&lt;br /&gt;
    const function int GetFactorial() {&lt;br /&gt;
        var result = 1;&lt;br /&gt;
        for (var x = this; x &amp;gt; 1; x--)&lt;br /&gt;
            result *= x;&lt;br /&gt;
        return result;&lt;br /&gt;
    }&lt;br /&gt;
    property int factorial read GetFactorial;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
export function main() {&lt;br /&gt;
    puts(&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;
;3-11: Мы объявляем расширение класса &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;
;14: Здесь мы видим применение расширения в действии. Константа 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;puts()&amp;lt;/tt&amp;gt;, принимает в качестве параметра [[Стандартные типы данных#Строки|строку]], в то время как тип свойства определен как &amp;lt;tt&amp;gt;[[Стандартные типы данных#Целые числа|int]]&amp;lt;/tt&amp;gt;. В этом нет ничего странного, потому что класс &amp;lt;tt&amp;gt;int&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;
&amp;lt;!-- '''Примечание:''' При работе с расширениями существует одно важное ограничение. Расширять классы можно только методами и свойствами, но не полями. Это связано с внутренней организацией языка К++ и виртуальной машины. Дополнительно стоит отметить, что методы объявленные в расширении будут перекрывать соответствующие им методы класса (имеется в виду ситуация когда имена и наборы параметров полностью совпадают). Важно понимать, что такое перекрытие не является объявлением виртуального метода — происходит именно замещение старого метода новым. --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Смотри также ==&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/K%2B%2B</id>
		<title>K++</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/K%2B%2B"/>
				<updated>2009-10-26T11:15:57Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* Синтаксис языка */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
[[Изображение:head.png]]&lt;br /&gt;
&lt;br /&gt;
По мере разработки платформы Диптаун, нами была осознана необходимость создания удобного и универсального средства для управления платформой. Изначально, мы хотели реализовать ее так, чтобы платформа была максимально гибкой и расширяемой; чтобы она позволяла вносить изменения практически в любую ее часть без необходимости пересмотра и переработки системы в целом. Неотъемлемой частью существующей реализации является [[виртуальная машина Gide]], которая берет на себя большую часть задач по управлению различными частями платформы и организации их взаимодействия. Gide применяется практически во всех задачах: начиная от генерации процедурных текстур и до пользовательского интерфейса; от управления аватарами и до программирования объектов виртуального пространства.&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;
* © Дмитрий Кашицын, 2007-2009&lt;br /&gt;
* © Дмитрий Роот, 2007-2009  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Введение ==&lt;br /&gt;
&lt;br /&gt;
# [[Предисловие]]&lt;br /&gt;
## [[Предисловие#Роль K++ в проекте Диптаун|Роль K++ в проекте Диптаун]]&lt;br /&gt;
## [[Предисловие#Почему именно K++?|Почему именно K++?]]&lt;br /&gt;
## [[Предисловие#Для кого эта книга|Для кого эта книга]]&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;
## [[Введение, или краткий обзор#Использование блоков|Использование блоков]]&lt;br /&gt;
## [[Введение, или краткий обзор#Расширение классов|Расширение классов]]&lt;br /&gt;
# [[Переменные]] &lt;br /&gt;
## [[Переменные#Понятие переменной, тип переменной|Понятие переменной, тип переменной]]&lt;br /&gt;
## [[Переменные#Статическая типизация на примере C++|Статическая типизация на примере C++]]&lt;br /&gt;
## [[Переменные#Динамическая типизация на примере Ruby|Динамическая типизация на примере Ruby]]&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;
## [[Классы и объекты#Понятие объекта|Понятие объекта]]&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;
## [[Функции#Аргументы|Аргументы]]&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;
### [[Основные синтаксические конструкции#Оператор if|Оператор if]]&lt;br /&gt;
### [[Основные синтаксические конструкции#Оператор if-else|Оператор if-else]]&lt;br /&gt;
### [[Основные синтаксические конструкции#Оператор if-elsif-else|Оператор if-elsif-else]]&lt;br /&gt;
### [[Основные синтаксические конструкции#Постфиксные операторы|Постфиксные операторы]] &lt;br /&gt;
### [[Основные синтаксические конструкции#Тернарный условный оператор|Тернарный условный оператор]]&lt;br /&gt;
## [[Основные синтаксические конструкции#Оператор множественного выбора (switch)|Оператор множественного выбора (switch)]]&lt;br /&gt;
## [[Основные синтаксические конструкции#Циклы|Циклы]]&lt;br /&gt;
### [[Основные синтаксические конструкции#Цикл while|Цикл while]] &lt;br /&gt;
### [[Основные синтаксические конструкции#Цикл for|Цикл for]]&lt;br /&gt;
### [[Основные синтаксические конструкции#Цикл foreach|Цикл foreach]]&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;
## [[Управление пакетами#Импортирование библиотек, ключевое слово import|Импортирование библиотек, ключевое слово import]] &lt;br /&gt;
## [[Управление пакетами#Ключевое слово package|Ключевое слово package]]&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;
## [[Типы операторов#Аксессоры и мутаторы|Аксессоры и мутаторы]]&lt;br /&gt;
# [[Использование операторов]]&lt;br /&gt;
&lt;br /&gt;
== Системная библиотека ==&lt;br /&gt;
&lt;br /&gt;
== GIDE == &lt;br /&gt;
&lt;br /&gt;
# [[Идеология gide]]&lt;br /&gt;
# [[Виртуальная машина gide]]&lt;br /&gt;
# [[Стандартная библиотека gide]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Рабочие заметки]]&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%9E%D0%B1%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0_%D0%B8%D1%81%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B9</id>
		<title>Обработка исключений</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%9E%D0%B1%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0_%D0%B8%D1%81%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B9"/>
				<updated>2009-10-24T13:00:46Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* Перехват исключений */&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;
Все вышеперечисленные события так или иначе могут произойти в ходе работы программы, однако, с точностью предсказать их практически невозможно, можно только оценить вероятность. Хорошая программа так и делает: в тех местах, где могут потенциально произойти исключительные ситуации, вставляется код, проверяющий состояние и производящий некоторые действия по &amp;quot;ликвидации последствий&amp;quot;. Например, в случае ошибки связи, программа может попытаться установить соединение заново, в то время как при ошибке внезапного конца файла, остается только уведомить об этом пользователя, показав соответствующее сообщение об ошибке.&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;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
    /* try-блок (основное тело) */&lt;br /&gt;
} catch (/* переменная для объекта исключения 1 */) {&lt;br /&gt;
    /* код перехватчика 1 */&lt;br /&gt;
} catch (/* переменная для объекта исключения 2 */) {&lt;br /&gt;
    /* код перехватчика 2 */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ключевое слово &amp;lt;tt&amp;gt;'''try'''&amp;lt;/tt&amp;gt; объявляет начало защищенного блока. Затем, идет основное тело или try-блок, в котором содержатся конструкции, соответствующие нормальной работе. В примере с файлом, здесь будет находиться код чтения содержимого файла и, возможно, его обработки. Если в ходе выполнения этого блока, возникнет исключительная ситуация, то управление будет передано одному из блоков обработки, соответствующему типу возникшего исключения (об этом чуть позже). В круглых скобках указывается имя переменной, которой будет назначен ''объект исключения'' — объект некоторого класса, который был &amp;quot;выброшен&amp;quot; из кода в качестве исключения.&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;
Код, который первым обнаруживает исключительную ситуацию (то есть, стоит у ее истоков) и желающий сообщить о ней &amp;quot;наверх&amp;quot;, должен создать объект исключения и &amp;quot;выбросить&amp;quot; его. Создается объект так же, как и любой другой объект в языке К++: либо с помощью оператора &amp;lt;tt&amp;gt;'''new'''&amp;lt;/tt&amp;gt;, либо с помощью [[Классы и объекты#Конструкторы|конструктора]] (если он предусмотрен). &amp;quot;Выбрасывание&amp;quot; объекта осуществляется с помощью специального оператора &amp;lt;tt&amp;gt;'''throw'''&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;
function Process(const int idx) {&lt;br /&gt;
    if (! idx in 5 .. 10)&lt;br /&gt;
        throw &amp;quot;индекс должен быть в диапазоне от 5 до 10&amp;quot;;&lt;br /&gt;
    /* нормальный код обработки */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В первой строке тела функции, проверяется условие, необходимое функции для работы. Если условие не выполняется, то производится генерация исключения, причем в качестве объекта исключения выступает объект строки. &lt;br /&gt;
&lt;br /&gt;
На практике применяются специальные классы распространенных исключений, которые объявлены в [[Стандартная библиотека Gide|стандартной библиотеке]]. Таким образом, все языки использующие стандартную библиотеку и умеющие работать с исключениями, смогут успешно взаимодействовать с помощью этого механизма.&lt;br /&gt;
&lt;br /&gt;
Приведем некоторые из наиболее распространенных классов исключений и поясним их назначение:&lt;br /&gt;
&lt;br /&gt;
::{| width=60%&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EInvalidCall&amp;lt;/tt&amp;gt; || неверный вызов (входные данные неверны)&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EFailed&amp;lt;/tt&amp;gt; || операция не удалась (и все тут)&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EAagain&amp;lt;/tt&amp;gt; || по тем или иным причинам требуется повтор операции&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EDenied &amp;lt;/tt&amp;gt; || действие запрещено!&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;ECancelled &amp;lt;/tt&amp;gt; || операция была отменена (например пользователем)&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EAlready&amp;lt;/tt&amp;gt; || операция уже была выполнена&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;ERangeError&amp;lt;/tt&amp;gt; || ошибка диапазона (выход значения за допустимые границы)&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EDivisionByZero&amp;lt;/tt&amp;gt; || арифметическая ошибка деления на ноль&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;ETimeout  &amp;lt;/tt&amp;gt; || истекло время ожидания чего-либо&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EStreamError&amp;lt;/tt&amp;gt; || ошибка [[потока]]&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;ERegexpError&amp;lt;/tt&amp;gt; || ошибка при разборе [[регулярного выражения]]&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EAbstractError&amp;lt;/tt&amp;gt; || попытка вызова [[Классы и объекты#Методы|абстрактного метода]]&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Здесь приведены только наиболее общие описания классов. Более конкретная информация содержится в самом объекте исключения. Классы исключений необходимы для того, чтобы сортировать возникающие ошибки по типам, и на основе этой информации обрабатывать их различным образом.&lt;br /&gt;
&lt;br /&gt;
Например, в описанном выше случае, наиболее подходящим классом ошибки будет &amp;lt;tt&amp;gt;ERangeError&amp;lt;/tt&amp;gt;. Соответственно, код генерации ошибки можно написать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
throw ERangeError.create(&amp;quot;индекс должен быть в диапазоне от 5 до 10&amp;quot;);&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;'''catch'''&amp;lt;/tt&amp;gt;, следом за которым, в круглых скобках, идет описание переменной исключения, а затем, собственно, блок обработчика. Например, так мог бы выглядеть код вызова вышеописанной функции &amp;lt;tt&amp;gt;Process()&amp;lt;/tt&amp;gt; и обработки возникающего исключения, если бы оно имело место:&lt;br /&gt;
&amp;lt;source lang=kpp&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
    Process(/*выражение задающее индекс*/);&lt;br /&gt;
    /* другой код */&lt;br /&gt;
} catch (e) {&lt;br /&gt;
    print(&amp;quot;Ошибка обработки индекса. #{e.name}: #{e.description}\n&amp;quot;);&lt;br /&gt;
    /* код обработки исключения */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для того чтобы сослаться на объект исключения используется переменная ''e''. Все системные классы исключений имеют свойства &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; и &amp;lt;tt&amp;gt;description&amp;lt;/tt&amp;gt;. Первое содержит имя исключения, а второе — описание ошибки. &lt;br /&gt;
&lt;br /&gt;
В зависимости от класса исключения могут добавляться дополнительные поля, более точно характеризующие ошибку. Для того чтобы можно было классифицировать объект исключения по его классу (пардон за каламбур), применяется расширенная форма конструкции перехвата:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=kpp&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
    /* защищаемый код */&lt;br /&gt;
} catch (/*класс 1*/ /*имя объекта 1*/) {&lt;br /&gt;
    /* код обработки исключения 1 */&lt;br /&gt;
} catch (/*класс 2*/ /*имя объекта 2*/) {&lt;br /&gt;
    /* код обработки исключения 2 */&lt;br /&gt;
...&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=kpp&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
    /* защищаемый код */&lt;br /&gt;
} catch (EAgain e) {&lt;br /&gt;
    /* запрос у пользователя на повторение операции */&lt;br /&gt;
} catch (ERangeError e) {&lt;br /&gt;
    /* отображение ошибки */&lt;br /&gt;
} catch (e) {&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;'''[[Основные синтаксические конструкции#Оператор множественного выбора (switch)|switch]]'''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Примечание 1:''' следует помнить, что правильность разбора исключений по классам, зависит от очередности расположения блоков перехватчиков в конструкции. При перехвате исключения выбор обработчика происходит по принципу первого совпадения, при котором проверяется, имеет ли объект исключения в своей иерархии класс, указанный в перехватчике. Если скажем, перехватчик &amp;lt;tt&amp;gt;'''catch''' (e)&amp;lt;/tt&amp;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;
&amp;lt;!--Приведем парочку примеров разных ситуаций, иллюстирующих проблему. Допустим, мы пишем библиотечный код работы с сетевыми соединениями, который представляет собой надстройку над сокетами. В процессе чтения из сокеты мы можем столкнуться с ошибкой чтения.--&amp;gt;&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%9E%D0%B1%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0_%D0%B8%D1%81%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B9</id>
		<title>Обработка исключений</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%9E%D0%B1%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0_%D0%B8%D1%81%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B9"/>
				<updated>2009-10-24T12:44:20Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* Генерация исключения */&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;
Все вышеперечисленные события так или иначе могут произойти в ходе работы программы, однако, с точностью предсказать их практически невозможно, можно только оценить вероятность. Хорошая программа так и делает: в тех местах, где могут потенциально произойти исключительные ситуации, вставляется код, проверяющий состояние и производящий некоторые действия по &amp;quot;ликвидации последствий&amp;quot;. Например, в случае ошибки связи, программа может попытаться установить соединение заново, в то время как при ошибке внезапного конца файла, остается только уведомить об этом пользователя, показав соответствующее сообщение об ошибке.&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;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
    /* try-блок (основное тело) */&lt;br /&gt;
} catch (/* переменная для объекта исключения 1 */) {&lt;br /&gt;
    /* код перехватчика 1 */&lt;br /&gt;
} catch (/* переменная для объекта исключения 2 */) {&lt;br /&gt;
    /* код перехватчика 2 */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ключевое слово &amp;lt;tt&amp;gt;'''try'''&amp;lt;/tt&amp;gt; объявляет начало защищенного блока. Затем, идет основное тело или try-блок, в котором содержатся конструкции, соответствующие нормальной работе. В примере с файлом, здесь будет находиться код чтения содержимого файла и, возможно, его обработки. Если в ходе выполнения этого блока, возникнет исключительная ситуация, то управление будет передано одному из блоков обработки, соответствующему типу возникшего исключения (об этом чуть позже). В круглых скобках указывается имя переменной, которой будет назначен ''объект исключения'' — объект некоторого класса, который был &amp;quot;выброшен&amp;quot; из кода в качестве исключения.&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;
Код, который первым обнаруживает исключительную ситуацию (то есть, стоит у ее истоков) и желающий сообщить о ней &amp;quot;наверх&amp;quot;, должен создать объект исключения и &amp;quot;выбросить&amp;quot; его. Создается объект так же, как и любой другой объект в языке К++: либо с помощью оператора &amp;lt;tt&amp;gt;'''new'''&amp;lt;/tt&amp;gt;, либо с помощью [[Классы и объекты#Конструкторы|конструктора]] (если он предусмотрен). &amp;quot;Выбрасывание&amp;quot; объекта осуществляется с помощью специального оператора &amp;lt;tt&amp;gt;'''throw'''&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;
function Process(const int idx) {&lt;br /&gt;
    if (! idx in 5 .. 10)&lt;br /&gt;
        throw &amp;quot;индекс должен быть в диапазоне от 5 до 10&amp;quot;;&lt;br /&gt;
    /* нормальный код обработки */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В первой строке тела функции, проверяется условие, необходимое функции для работы. Если условие не выполняется, то производится генерация исключения, причем в качестве объекта исключения выступает объект строки. &lt;br /&gt;
&lt;br /&gt;
На практике применяются специальные классы распространенных исключений, которые объявлены в [[Стандартная библиотека Gide|стандартной библиотеке]]. Таким образом, все языки использующие стандартную библиотеку и умеющие работать с исключениями, смогут успешно взаимодействовать с помощью этого механизма.&lt;br /&gt;
&lt;br /&gt;
Приведем некоторые из наиболее распространенных классов исключений и поясним их назначение:&lt;br /&gt;
&lt;br /&gt;
::{| width=60%&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EInvalidCall&amp;lt;/tt&amp;gt; || неверный вызов (входные данные неверны)&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EFailed&amp;lt;/tt&amp;gt; || операция не удалась (и все тут)&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EAagain&amp;lt;/tt&amp;gt; || по тем или иным причинам требуется повтор операции&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EDenied &amp;lt;/tt&amp;gt; || действие запрещено!&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;ECancelled &amp;lt;/tt&amp;gt; || операция была отменена (например пользователем)&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EAlready&amp;lt;/tt&amp;gt; || операция уже была выполнена&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;ERangeError&amp;lt;/tt&amp;gt; || ошибка диапазона (выход значения за допустимые границы)&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EDivisionByZero&amp;lt;/tt&amp;gt; || арифметическая ошибка деления на ноль&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;ETimeout  &amp;lt;/tt&amp;gt; || истекло время ожидания чего-либо&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EStreamError&amp;lt;/tt&amp;gt; || ошибка [[потока]]&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;ERegexpError&amp;lt;/tt&amp;gt; || ошибка при разборе [[регулярного выражения]]&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tt&amp;gt;EAbstractError&amp;lt;/tt&amp;gt; || попытка вызова [[Классы и объекты#Методы|абстрактного метода]]&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Здесь приведены только наиболее общие описания классов. Более конкретная информация содержится в самом объекте исключения. Классы исключений необходимы для того, чтобы сортировать возникающие ошибки по типам, и на основе этой информации обрабатывать их различным образом.&lt;br /&gt;
&lt;br /&gt;
Например, в описанном выше случае, наиболее подходящим классом ошибки будет &amp;lt;tt&amp;gt;ERangeError&amp;lt;/tt&amp;gt;. Соответственно, код генерации ошибки можно написать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
throw ERangeError.create(&amp;quot;индекс должен быть в диапазоне от 5 до 10&amp;quot;);&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;'''catch'''&amp;lt;/tt&amp;gt;, следом за которым, в круглых скобках, идет описание переменной исключения, а затем, собственно, блок обработчика. Например, так мог бы выглядеть код вызова вышеописанной функции &amp;lt;tt&amp;gt;Process()&amp;lt;/tt&amp;gt; и обработки возникающего исключения, если бы оно имело место:&lt;br /&gt;
&amp;lt;source lang=kpp&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
    Process(/*выражение задающее индекс*/);&lt;br /&gt;
    /* другой код */&lt;br /&gt;
} catch (e) {&lt;br /&gt;
    print(&amp;quot;Ошибка обработки индекса. #{e.name}: #{e.description}\n&amp;quot;);&lt;br /&gt;
    /* код обработки исключения */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для того чтобы сослаться на объект исключения используется переменная ''e''. Все системные классы исключений имеют свойства &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; и &amp;lt;tt&amp;gt;description&amp;lt;/tt&amp;gt;. Первое содержит имя исключения, а второе — описание ошибки. &lt;br /&gt;
&lt;br /&gt;
В зависимости от класса исключения могут добавляться дополнительные поля, более точно характеризующие ошибку. Для того чтобы можно было классифицировать объект исключения по его классу (пардон за каламбур), применяется расширенная форма конструкции перехвата:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=kpp&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
    /* защищаемый код */&lt;br /&gt;
} catch (/*класс 1*/ /*имя объекта 1*/) {&lt;br /&gt;
    /* код обработки исключения 1 */&lt;br /&gt;
} catch (/*класс 2*/ /*имя объекта 2*/) {&lt;br /&gt;
    /* код обработки исключения 2 */&lt;br /&gt;
...&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=kpp&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
    /* защищаемый код */&lt;br /&gt;
} catch (e_again e) {&lt;br /&gt;
    /* запрос у пользователя на повторение операции */&lt;br /&gt;
} catch (e_range_error e) {&lt;br /&gt;
    /* отображение ошибки */&lt;br /&gt;
} catch (e) {&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;'''[[Основные синтаксические конструкции#Оператор множественного выбора (switch)|switch]]'''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' следует помнить, что правильность разбора исключений по классам, зависит от очередности расположения блоков перехватчиков в конструкции. При перехвате исключения выбор обработчика происходит по принципу первого совпадения, при котором проверяется, имеет ли объект исключения в своей иерархии класс, указанный в перехватчике. Если скажем, перехватчик &amp;lt;tt&amp;gt;'''catch''' (e)&amp;lt;/tt&amp;gt; будет указан первым, то он и будет собирать все исключения, поскольку он сработает на любой класс объекта исключения. Вообще, нужно стараться располагать перехватчики по убыванию степени абстракции — от пользовательских классов до системных и далее, до общего перехватчика.&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/Bytea</id>
		<title>Bytea</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/Bytea"/>
				<updated>2009-06-25T15:31:16Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* оператор + */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Класс &amp;lt;tt&amp;gt;bytea&amp;lt;/tt&amp;gt; (от англ. ''byte array'' — массив байтов) используется для работы с данными, как с потоком байтов. Класс во многом похож на класс &amp;lt;tt&amp;gt;[[string]]&amp;lt;/tt&amp;gt;. Отличие заключается в том, что &amp;lt;tt&amp;gt;[[string]]&amp;lt;/tt&amp;gt; ориентируется на строковые данные в кодировке '''UTF-8''', в то время как &amp;lt;tt&amp;gt;bytea&amp;lt;/tt&amp;gt; ориентируется на байты. &lt;br /&gt;
&lt;br /&gt;
Например, в случае строки &amp;quot;hello world&amp;quot; методы &amp;lt;tt&amp;gt;[[#length|bytea:length]]&amp;lt;/tt&amp;gt; и &amp;lt;tt&amp;gt;[[string#length|string:length]]&amp;lt;/tt&amp;gt; вернут одно и то же число, поскольку байтовое представление будет одинаковым. В случае строки &amp;quot;привет мир&amp;quot;, длины уже не будут совпадать, поскольку в кодировке '''UTF-8''' символы кирилицы будут представляться уже двумя байтами.&lt;br /&gt;
&lt;br /&gt;
'''Родители''': &amp;lt;tt&amp;gt;[[Object]]&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
'''Методы''': &amp;lt;tt&amp;gt;&lt;br /&gt;
[[#empty|empty]] &lt;br /&gt;
[[#length|length]] &lt;br /&gt;
[[#resize|resize]] &lt;br /&gt;
[[#clear|clear]] &lt;br /&gt;
[[#substr|substr]] &lt;br /&gt;
[[#replace|replace]] &lt;br /&gt;
[[#replace_all|replace_all]] &lt;br /&gt;
[[#insert|insert]] &lt;br /&gt;
[[#erase|erase]] &lt;br /&gt;
[[#find|find]] &lt;br /&gt;
[[#find_first_of|find_first_of]] &lt;br /&gt;
[[#find_first_not_of|find_first_not_of]]&amp;lt;/tt&amp;gt; &lt;br /&gt;
'''Приводится к типам''': &amp;lt;tt&amp;gt;[[int]] [[real]] [[uid]] [[string]]&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
'''Реализует операторы''': &lt;br /&gt;
&amp;lt;tt&amp;gt;[[#оператор +|+]]&amp;lt;/tt&amp;gt;,&lt;br /&gt;
&amp;lt;tt&amp;gt;[[#оператор +=|+=]]&amp;lt;/tt&amp;gt;, &lt;br /&gt;
&amp;lt;tt&amp;gt;[[#оператор &amp;lt;&amp;lt;|&amp;lt;&amp;lt;]]&amp;lt;/tt&amp;gt;, &lt;br /&gt;
[[#индексные операторы|индексного доступа]],&lt;br /&gt;
[[оператор присваивания|присваивания]],&lt;br /&gt;
[[операторы сравнения|сравнения]] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
&lt;br /&gt;
== индексные операторы  ==&lt;br /&gt;
&lt;br /&gt;
operator &amp;lt;nowiki&amp;gt;[]&amp;lt;/nowiki&amp;gt; (''индекс'': &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Оператор индексного чтения служит для получения значения некоторого байта расположенного по указанному индексу. Если указан индекс, выходящий за текущие границы массива, будет сгенерировано исключение [[Классы исключений#ERangeError|ERangeError]].&lt;br /&gt;
&lt;br /&gt;
operator &amp;lt;nowiki&amp;gt;[]=&amp;lt;/nowiki&amp;gt; (''индекс'': &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;, ''значение'': &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Оператор индексной записи, напротив, служит для установки значения байта расположенного по соответствующему индексу. Если указан индекс, выходящий за текущие границы массива, будет сгенерировано исключение [[Классы исключений#ERangeError|ERangeError]].&lt;br /&gt;
&lt;br /&gt;
'''Примечание''': Имеет значение только самый младший байт переданного числа, то есть значения в диапазоне от 0 до 255.&lt;br /&gt;
&lt;br /&gt;
== оператор + ==&lt;br /&gt;
&lt;br /&gt;
operator + (''слагаемое'': &amp;lt;tt&amp;gt;bytea&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': &amp;lt;tt&amp;gt;bytea&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод возвращает новый байт-массив, полученный путем конкатенации (сложения) текущего и переданного массивов. Размер внутреннего буфера увеличивается автоматически, однако в случае большого количества последовательных (циклических) конкатенаций, возможен предварительный вызов метода &amp;lt;tt&amp;gt;[[#resie|resize]]&amp;lt;/tt&amp;gt;, для повышения быстродействия и уменьшения числа промежуточных операций копирования.&lt;br /&gt;
&lt;br /&gt;
== оператор += ==&lt;br /&gt;
&lt;br /&gt;
operator += (''слагаемое'': &amp;lt;tt&amp;gt;bytea&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': текущий объект &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод изменяет текущий массив, дописывая ему в конец массив, переданный в качестве параметра. Размер внутреннего буфера увеличивается автоматически, однако в случае большого количества последовательных (циклических) конкатенаций, возможен предварительный вызов метода &amp;lt;tt&amp;gt;[[#resie|resize]]&amp;lt;/tt&amp;gt; для повышения быстродействия и уменьшения числа промежуточных операций копирования.&lt;br /&gt;
&lt;br /&gt;
== оператор &amp;lt;&amp;lt; ==&lt;br /&gt;
&lt;br /&gt;
Эквивалент оператора &amp;lt;tt&amp;gt;[[#оператор +|+]]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== empty ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': [[логическое значение]] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод возвращает истину, если массив непуст. &lt;br /&gt;
&lt;br /&gt;
== length ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': &amp;lt;tt&amp;gt;[[int]]&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод возвращает текущий размер данных в байтах. &lt;br /&gt;
&lt;br /&gt;
== resize ==&lt;br /&gt;
&lt;br /&gt;
resize(''новый размер в байтах'': &amp;lt;tt&amp;gt;[[int]]&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': текущий объект &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод изменяет размер внутреннего буфера, устанавливая его равным переданному числу. При увеличении размера буфера, данные останутся нетронутыми, однако незанятая область будет содержать случайные данные.&lt;br /&gt;
&lt;br /&gt;
== clear ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': текущий объект &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Очищает массив содержимого и сбрасывает внутренний буфер. После этого строка считается пустой.&lt;br /&gt;
&lt;br /&gt;
== substr ==&lt;br /&gt;
&lt;br /&gt;
substr(''начальная позиция:'' &amp;lt;tt&amp;gt;[[int]]&amp;lt;/tt&amp;gt;, ''количество байт'': &amp;lt;tt&amp;gt;[[int]]&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': &amp;lt;tt&amp;gt;bytea&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод возвращает байт-массив, содержащий подмассив текущих данных, начиная с указанной позиции.&lt;br /&gt;
&lt;br /&gt;
== replace ==&lt;br /&gt;
&lt;br /&gt;
replace(''начальная позиция'': &amp;lt;tt&amp;gt;[[int]]&amp;lt;/tt&amp;gt;, ''количество байт'': &amp;lt;tt&amp;gt;[[int]]&amp;lt;/tt&amp;gt;, ''блок замены'': &amp;lt;tt&amp;gt;bytea&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': текущий объект &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод заменяет указанное количество байт с начальной позиции на блок замены.&lt;br /&gt;
&lt;br /&gt;
== replace_all ==&lt;br /&gt;
&lt;br /&gt;
replace_all(''блок поиска'': &amp;lt;tt&amp;gt;bytea&amp;lt;/tt&amp;gt;, ''блок замены'': &amp;lt;tt&amp;gt;bytea&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': текущий объект &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод находит все включения блока поиска в исходном массиве и заменяет их на блок замены.&lt;br /&gt;
&lt;br /&gt;
== insert ==&lt;br /&gt;
&lt;br /&gt;
insert(''позиция'': &amp;lt;tt&amp;gt;[[int]]&amp;lt;/tt&amp;gt;, ''данные'': &amp;lt;tt&amp;gt;bytea&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': текущий объект &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод вставляет переданные данные в исходныый массив, в указаную позицию, &amp;quot;раздвигая&amp;quot; имеющиеся данные.&lt;br /&gt;
&lt;br /&gt;
== erase ==&lt;br /&gt;
&lt;br /&gt;
erase_int(''начальная позиция:'' &amp;lt;tt&amp;gt;[[int]]&amp;lt;/tt&amp;gt;, ''количество байт'': &amp;lt;tt&amp;gt;[[int]]&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': текущий объект &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод вырезает из текущих данных указанный блок.&lt;br /&gt;
&lt;br /&gt;
== find ==&lt;br /&gt;
&lt;br /&gt;
find(''блок поиска'': &amp;lt;tt&amp;gt;string&amp;lt;/tt&amp;gt; [, ''начальная позиция'': &amp;lt;tt&amp;gt;[[int]]&amp;lt;/tt&amp;gt;]) &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': &amp;lt;tt&amp;gt;[[int]]&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод ищет в исходных данных искомый блок и возвращает его смещение. Для поиска блока, начиная с некоторой позиции, может быть передан второй параметр — смещение начальной позиции.&lt;br /&gt;
&lt;br /&gt;
== find_first_of ==&lt;br /&gt;
&lt;br /&gt;
== find_first_not_of ==&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/Object</id>
		<title>Object</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/Object"/>
				<updated>2009-06-18T14:27:07Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* inspect */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Класс &amp;lt;tt&amp;gt;Object&amp;lt;/tt&amp;gt; является сердцем всей стандартной библиотеки и ее центральным классом. Все остальные классы, прямо или косвенно наследуются от &amp;lt;tt&amp;gt;Object&amp;lt;/tt&amp;gt;, что позволяет реализовывать централизованное управление и сбор информации об объектах. Данный класс имеет набор методов которые реализуют механизм рефлексии, который заключается в том, что объекты могут динамически получать информацию о других объектах (включая самих себя). Например, объект A может узнать, какие методы имеет объект B, и на основании этой информации выполнять те или иные действия. &lt;br /&gt;
&lt;br /&gt;
Класс &amp;lt;tt&amp;gt;Object&amp;lt;/tt&amp;gt; вводит понятие инспектирования объектов, которое позволяет получать сведения о содержимом объектов в удобной для восприятия форме (это может быть особенно полезно при отладке и трассировке программ).&lt;br /&gt;
&lt;br /&gt;
'''Родители''': &amp;lt;tt&amp;gt;Object&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
'''Методы''': &amp;lt;tt&amp;gt;[[#class|class]] [[#className|className]] [[#instanceOf|instanceOf]] [[#call|call]] [[#invoke|invoke]] [[#freeze|freeze]] [[#frozen|frozen]] [[#clone|clone]] [[#dup|dup]] [[#inspect|inspect]] [[#equals|equals]] [[#hasMethod|hasMethod]] [[#getMethod|getMethod]] [[#methods|methods]]&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
'''Реализует операторы''': &amp;lt;tt&amp;gt;[[#equals|==]]&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
&lt;br /&gt;
== class ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': &amp;lt;tt&amp;gt;[[Class]]&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод возвращает инстанцию класса &amp;lt;tt&amp;gt;[[Class]]&amp;lt;/tt&amp;gt;, соответствующую классу данного объекта. Например:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var x = 1;        //переменная типа int&lt;br /&gt;
var c = x.class;  //переменная типа Class&lt;br /&gt;
puts(c.name);     //выведет на экран строку &amp;quot;int&amp;quot;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== className ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': &amp;lt;tt&amp;gt;[[string]]&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Эквивалент операции &amp;lt;tt&amp;gt;x.class.name&amp;lt;/tt&amp;gt;, только работает быстрее (без создания промежуточного объекта)&lt;br /&gt;
&lt;br /&gt;
== instanceOf ==&lt;br /&gt;
&lt;br /&gt;
instanceOf(''имя класса:'' &amp;lt;tt&amp;gt;[[string]]&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
instanceOf(''класс:'' &amp;lt;tt&amp;gt;[[Class]]&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': [[логическое значение]] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяет, является ли текущий объект инстанцией указанного класса.&lt;br /&gt;
&lt;br /&gt;
== call ==&lt;br /&gt;
&lt;br /&gt;
call(''имя метода:'' &amp;lt;tt&amp;gt;[[string]]&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;'''...'''&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': динамическую переменную &amp;lt;br&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 ary = new array; &lt;br /&gt;
ary.call(:push, 1, 2, 3);&lt;br /&gt;
puts(ary.inspect); // [1, 2, 3]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== invoke ==&lt;br /&gt;
&lt;br /&gt;
invoke(''имя метода:'' &amp;lt;tt&amp;gt;[[string]]&amp;lt;/tt&amp;gt;, ''параметры:'' &amp;lt;tt&amp;gt;[[array]]&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': динамическую переменную &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод аналогичен по смыслу методу &amp;lt;tt&amp;gt;[[#call|call]]&amp;lt;/tt&amp;gt;, за исключением того, что последующие параметры передаются в массиве. При вызове этот массив будет &amp;quot;развернут&amp;quot;, как если бы все параметры были записаны через запятую:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var ary = new array; &lt;br /&gt;
ary.invoke(:push, [1, 2, 3]);&lt;br /&gt;
puts(ary.inspect); // [1, 2, 3]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== freeze ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': текущий объект &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод &amp;quot;замораживает&amp;quot; текущий объект, после чего он становится доступным только для чтения. Обратной операции не существует, так что разморозить однажды замороженный объект нельзя.&lt;br /&gt;
&lt;br /&gt;
== frozen ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': [[логическое значение]] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяет, является ли текущий объект замороженным.&lt;br /&gt;
&lt;br /&gt;
== clone ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': копию текущего объекта &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод служит для создания копии текущего объекта, используя оператор &amp;quot;&amp;lt;tt&amp;gt;=&amp;lt;/tt&amp;gt;&amp;quot;. Если объект (или его класс) располагает таким методом, будет создана пустая инстанция класса, которой будет присвоено значение текущего объекта.&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' В случае с контейнерами копирование происходит только в том случае, если данный элемент обладает оператором &amp;quot;&amp;lt;tt&amp;gt;=&amp;lt;/tt&amp;gt;&amp;quot;; в противном случае, в копии контейнера будет лежать тот же объект:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var ary = new array; &lt;br /&gt;
ary.push(5);&lt;br /&gt;
ary.push(Stream.open(...));&lt;br /&gt;
var copy = ary.clone;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В этом примере, переменная ''copy'' будет содержать копию оригинального массива ''ary''. Однако скопирован будет только нулевой элемент массива, то есть объект соответствующий константе 5. Инстанция потока будет передана &amp;quot;как есть&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== dup ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== inspect ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': &amp;lt;tt&amp;gt;[[string]]&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод преобразует и возвращает информацию об объекте в удобном для восприятия виде. Переопределяется в классах-потомках для отображения более детальной информации. Во многих случаях является аналогом оператора приведения к строке, однако не всегда. Например, в случае K++, для класса строки оператор приведения к типу &amp;lt;tt&amp;gt;[[string]]&amp;lt;/tt&amp;gt; возвращает саму строку, тогда как метод &amp;lt;tt&amp;gt;inspect&amp;lt;/tt&amp;gt; возвращает строку с восстановленными спецсимволами и заключенную в кавычки:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var hello = &amp;quot;hello\tworld\n&amp;quot;;&lt;br /&gt;
puts(hello);           //вывод: hello    world&lt;br /&gt;
puts(hello as string); //вывод: hello    world&lt;br /&gt;
puts(hello.inspect);   //вывод: &amp;quot;hello\tworld\n&amp;quot;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Другие классы, такие как контейнеры, переопределяют метод для отображения своего содержимого. При этом, в коде метода рекурсивно вызывается метод &amp;lt;tt&amp;gt;inspect&amp;lt;/tt&amp;gt; самих элементов для отображения их значения:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var ary = [1, [2,'3'], :x, { :a =&amp;gt; 1 }];&lt;br /&gt;
puts(ary.inspect);  //вывод: [1, [2, &amp;quot;3&amp;quot;], &amp;quot;x&amp;quot;, { &amp;quot;a&amp;quot; =&amp;gt; 1 }]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== equals ==&lt;br /&gt;
&lt;br /&gt;
equals(''объект сравнения'') &amp;lt;br&amp;gt;&lt;br /&gt;
operator == (''объект сравнения'') &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': [[логическое значение]] &amp;lt;br&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 x = 5;&lt;br /&gt;
var b1 = x.equals(x);&lt;br /&gt;
var y = 4 + 1;&lt;br /&gt;
var b2 = x.equals(y);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В этом примере переменная ''b1'' будет истинной, в то время как переменная ''b2'' ложной. Несмотря на то, что переменные ''x'' и ''y'' равны численно — они представлены разными объектами.&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' В случае с классом &amp;lt;tt&amp;gt;Object&amp;lt;/tt&amp;gt; для тех же целей может применяться и оператор &amp;lt;tt&amp;gt;==&amp;lt;/tt&amp;gt;, однако предполагается что он должен переопределяться дочерними классами для достижения собственных целей. Сам же метод &amp;lt;tt&amp;gt;equals&amp;lt;/tt&amp;gt; переопределяться не должен никогда (для обеспечения оригинального функционала).&lt;br /&gt;
&lt;br /&gt;
== hasMethod ==&lt;br /&gt;
&lt;br /&gt;
hasMethod(''имя метода:'' &amp;lt;tt&amp;gt;[[string]]&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': [[логическое значение]] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяет, имеет ли объект указанный метод.&lt;br /&gt;
&lt;br /&gt;
== getMethod ==&lt;br /&gt;
&lt;br /&gt;
getMethod(''имя метода:'' &amp;lt;tt&amp;gt;[[string]]&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': &amp;lt;tt&amp;gt;[[Method]]&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данный метод возвращает метод объекта в виде объекта метода =) Впоследствии, этот объект может использоваться для удаленного вызова метода, либо для получения дополнительной информации. При попытке получения несуществующего метода будет возбуждено исключение &amp;lt;tt&amp;gt;[[Классы исключений#ENotFound|ENotFound]]&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;
var ary = new array;&lt;br /&gt;
var p = ary.getMethod(:push);&lt;br /&gt;
p(1, 2, 3);&lt;br /&gt;
ary.inspect; //значение: [1, 2, 3]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== methods ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': &amp;lt;tt&amp;gt;[[array]]&amp;lt;[[string]]&amp;gt;&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод возвращает массив имен методов.&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' Результирующий массив создается по требованию при каждом вызове метода. Поэтому, при необходимости перебора элементов, следует сначала сохранить полученный массив в переменную, а затем работать уже с ней.&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%9F%D1%80%D0%B0%D0%B2%D0%B8%D0%BB%D0%B0_%D0%BE%D1%84%D0%BE%D1%80%D0%BC%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%BA%D0%BE%D0%B4%D0%B0</id>
		<title>Правила оформления кода</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%9F%D1%80%D0%B0%D0%B2%D0%B8%D0%BB%D0%B0_%D0%BE%D1%84%D0%BE%D1%80%D0%BC%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%BA%D0%BE%D0%B4%D0%B0"/>
				<updated>2009-05-18T14:53:42Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* Правила именования */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Введение ==&lt;br /&gt;
&lt;br /&gt;
На этой странице описаны правила оформления кода для библиотек и прикладных программ проекта Deeptown. Соблюдение этих правил не менее важно, чем качество кода: это повышает читаемость кода другими людьми. Несоблюдение этих правил может стать причиной отказа в принятии кода.&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;
Для интернациональных символов в проекте используется кодировка UTF-8. Вы можете использовать строки на русском и других языках прямо в коде программ - для этого нужно сохранить исходный код программы в кодировке UTF-8. Но помните, что это является плохим стилем: в хорошей программе, все интернациональные сообщения находятся в файлах данных.&lt;br /&gt;
&lt;br /&gt;
=== Подход к написанию кода ===&lt;br /&gt;
&lt;br /&gt;
Самое главное правило: код должен быть легкочитаем и красив.&lt;br /&gt;
&lt;br /&gt;
Диптаун - это очень большой проект, состоящий из множества модулей. Эти модули завязаны друг на друга, и правильное функционирование одних невозможно без других. Поэтому мы не приемлем write-only код.&lt;br /&gt;
&lt;br /&gt;
Для того, чтобы код получался красивым, прежде всего нужен творческий подход к его написанию. Поэтому мы не приводим каких-либо формальных правил по этому вопросу. Спорные ситуации будут решаться в дискуссиях.&lt;br /&gt;
&lt;br /&gt;
Очень советуем прочитать статью про [http://ru.wikipedia.org/wiki/%D0%90%D0%BD%D1%82%D0%B8-%D0%BF%D0%B0%D1%82%D1%82%D0%B5%D1%80%D0%BD анти-паттерны] в википедии.&lt;br /&gt;
&lt;br /&gt;
=== Комментарии ===&lt;br /&gt;
&lt;br /&gt;
Код должен быть откомментирован так, чтобы обеспечить его читаемость, но и не должен быть перегружен комментариями.&lt;br /&gt;
&lt;br /&gt;
Обычно для выполнения этого условия достаточно написать небольшие пояснения к каждому классу и методу в этом классе.&lt;br /&gt;
&lt;br /&gt;
Комментарии должны объяснять, '''как''' работает код, но не '''что''' он делает. Ответ на второй вопрос должен содержаться в документации, а не в коде; мы не используем в проекте системы вроде doxygen для создания документации из кода, поскольку убеждены, что документация в коде загромождает этот код и делает его трудночитаемым.&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;
 // project : &amp;lt;project name&amp;gt;&lt;br /&gt;
 // date    : &amp;lt;current date&amp;gt;&lt;br /&gt;
 // author  : &amp;lt;author name&amp;gt;&lt;br /&gt;
 // e-mail  : &amp;lt;author email&amp;gt;&lt;br /&gt;
 // licence : &amp;lt;licence name&amp;gt;&lt;br /&gt;
 //&lt;br /&gt;
&lt;br /&gt;
Имя проекта - это название задания в списке задач, переведенное на английский язык, например, - '''console programs'''. Дата - текущая дата в формате yyyy-mm-dd. Имя автора записывается в форме '''Имя Фамилия''' (также по-английски), например: '''Vasily Petrov''' (но не Petrov Vasily). E-mail - это актуальный адрес автора, который может быть использован для писем по вопросам работоспособности данного кода.&lt;br /&gt;
&lt;br /&gt;
Лицензия - это либо название одной из применяемых в проекте лицензий ('''MIT''', '''LGPL''' etc), либо имя файла с лицензией. Персональные лицензии должны храниться в файлах, содержащих имя автора в имени файла, например '''licence-petrov-vasily.txt'''. Все такие лицензии будут добавлены в репозиторий с кодом.&lt;br /&gt;
&lt;br /&gt;
После этого комментария может идти текст лицензии или какие-либо лицензионные предупреждения (некоторые лицензии это требуют). Но такой текст должен идти ПОСЛЕ заголовка, а не до него.&lt;br /&gt;
&lt;br /&gt;
Поля author и e-mail могут быть записаны несколько раз, в случае если авторов/адресов несколько.&lt;br /&gt;
&lt;br /&gt;
Строгость формата заголовка нужна в частности для того, чтобы можно было писать скрипты, собирающие статистику. Например, это будет использоваться скриптами, которые будут анализировать объемы работ различных авторов.&lt;br /&gt;
&lt;br /&gt;
Пример заголовочного комментария:&lt;br /&gt;
&lt;br /&gt;
 //&lt;br /&gt;
 // project : mysql database driver&lt;br /&gt;
 // date    : 2008-11-30&lt;br /&gt;
 // author  : Ivan Ivanov&lt;br /&gt;
 // e-mail  : ivan.ivanov@example.com&lt;br /&gt;
 // licence : MIT&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;
тело операторных скобок состоит из не более чем 10 строк. В этом случае &lt;br /&gt;
допускается открывающую операторную скобку поставить на ту же строку, что и &lt;br /&gt;
&amp;quot;породивший&amp;quot; ее оператор:&lt;br /&gt;
&lt;br /&gt;
 while(...) {&lt;br /&gt;
     // some stuff&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Кроме того, специальное исключение делается для конструкции if ... else:&lt;br /&gt;
&lt;br /&gt;
 if(...) {&lt;br /&gt;
     // stuff...&lt;br /&gt;
 } else {&lt;br /&gt;
     // more stuff...&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Исключение также применимо только для не слишком длинных конструкций.&lt;br /&gt;
&lt;br /&gt;
== Правила для K++ кода ==&lt;br /&gt;
&lt;br /&gt;
=== Правила именования ===&lt;br /&gt;
&lt;br /&gt;
(жирным отмечены обязательные правила, остальные - желательны, но не обязательны).&lt;br /&gt;
&lt;br /&gt;
# '''Модули именуются в стиле MyModuleName''';&lt;br /&gt;
# '''Имена файлов в точности совпадают с именами модулей'''. Например, модуль Proto::HTTP должен находиться в файле Proto/HTTP.kpp;&lt;br /&gt;
# '''Классы именуются в стиле MyClassName''', без каких-либо префиксов;&lt;br /&gt;
# '''Публичные методы и свойства именуются в стиле someMethodName''';&lt;br /&gt;
# '''Аргументы функций именуются в стиле argument_name''';&lt;br /&gt;
# '''Все публичные имена должны быть говорящими, желательно без сокращений, но при этом не слишком длинными'''. Примерное ограничение по длине имени - 20 символов;&lt;br /&gt;
# Приватные методы и свойства именуются аналогично публичным;&lt;br /&gt;
# Локальные переменные именуются в стиле variable_name (все буквы - строчные, символы подчеркивания между словами);&lt;br /&gt;
# Поля класса именуются аналогично локальным переменным, но с префиксом '''m_'''. &lt;br /&gt;
&lt;br /&gt;
Такой подход к именованию имеет множество плюсов. В нем практически не используются префиксы (которые обычно надоедают), но при этом стиль написания имен классов, методов и переменных различается, что облегчает читаемость кода.&lt;br /&gt;
&lt;br /&gt;
Обратите внимание, что мы требуем выполнения правил по именованию публичных частей модуля, но по именам &amp;quot;внутренней кухни&amp;quot; даем лишь рекомендации. Это сделано для обеспечения единообразия интерфейсов.&lt;br /&gt;
&lt;br /&gt;
== Правила для C++ кода ==&lt;br /&gt;
&lt;br /&gt;
Этот раздел скопирован из стандарта кода самого Диптауна. Возможно, некоторым не понравится такой стиль, но так уж исторически сложилось. Если возражений будет слишком много - мы напишем скрипт, который сконвертирует один стиль в другой. Но делать это будем централизованно. Сейчас в проекте принят такой стиль, и холивары по этому поводу очень нежелательны.&lt;br /&gt;
&lt;br /&gt;
=== Переносимость кода ===&lt;br /&gt;
&lt;br /&gt;
Весь код проекта должен компилироваться, собираться и работать на любой &lt;br /&gt;
системе, будь то Windows, Mac, UNIX, Solaris и другие. Использование &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;
* ''прописная слитная'' - объект должен быть назван прописными буквами, слова не должны отделяться друг от друга. Например, OBJECTNAME.&lt;br /&gt;
* ''прописная [раздельная]'' - объект должен быть назван прописными буквами, слова отделяются друг от друга знаком подчеркивания: OBJECT_NAME.&lt;br /&gt;
* ''строчная слитная'', ''строчная [раздельная]'' - аналогично: objectname и object_name соответственно.&lt;br /&gt;
* ''основная'' - название должно начинаться с прописной буквы, и каждое слово должно начинаться с прописной буквы. Остальные буквы - строчные: ObjectName.&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;
* все внутренние включаемые файлы должны находиться в подкаталоге ''impl'';&lt;br /&gt;
* все исходные файлы должны находиться в каталоге ''source''.&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;
Реализация каждого класса должна быть вынесена в отдельный исходный файл, имя &lt;br /&gt;
которого совпадает с именем класса.&lt;br /&gt;
&lt;br /&gt;
На разбиение реализаций отдельных функций по файлам ограничений не &lt;br /&gt;
накладывается.&lt;br /&gt;
&lt;br /&gt;
=== Пространства имен ===&lt;br /&gt;
&lt;br /&gt;
Все объявления каждого модуля должны быть внесены в отдельное пространство имен (namespace),&lt;br /&gt;
имя которого совпадает с именем модуля, записанного по основной схеме разыменовывания.&lt;br /&gt;
&lt;br /&gt;
=== Стражи включения ===&lt;br /&gt;
&lt;br /&gt;
Все файлы заголовков должны быть защищены стражем включения. Имя стража &lt;br /&gt;
включения дается следующему шаблону: __PRFX_FILENAME_H_INCLUDED.&lt;br /&gt;
&lt;br /&gt;
Здесь PRFX - префикс модуля и его части (см. п. 4.1), FILENAME - имя &lt;br /&gt;
заголовочного файла, записанное прописными буквами.&lt;br /&gt;
&lt;br /&gt;
Пример:&lt;br /&gt;
&lt;br /&gt;
 #ifndef __SEST_INDEXBUFFER_H_INCLUDED&lt;br /&gt;
 #define __SEST_INDEXBUFFER_H_INCLUDED&lt;br /&gt;
 // ...&lt;br /&gt;
 // ...&lt;br /&gt;
 #endif&lt;br /&gt;
 // EOF&lt;br /&gt;
&lt;br /&gt;
=== Правила именования сущностей ===&lt;br /&gt;
&lt;br /&gt;
Применяются следующие правила разыменовывания:&lt;br /&gt;
&lt;br /&gt;
* Определения препроцессора именуются по прописной схеме. Кроме того, для всех определений препроцессора ставится два префикса. Первый соответствует модулю и его части (4 символа), второй - смыслу определения. Префиксы отделяются друг от друга и от имени знаком подчеркивания. Пример: '''SEST_IBS_LOADED''' (Soung Engine, STreaming module; Index Buffer State).&lt;br /&gt;
* Интерфейсы (классы, в которых все методы - абстрактные) именуются по стандартной схеме, ставится префикс '''I''' (ISomeName).&lt;br /&gt;
* Классы именуются по стандартной схеме, ставится префикс '''C''' (CClassName).&lt;br /&gt;
* Структуры именуются по стандартной схеме (StructName).&lt;br /&gt;
* Функции и методы классов также именуются по стандартной схеме.&lt;br /&gt;
* Закрытые поля и локальные переменные именуются произвольно.&lt;br /&gt;
* Публичные поля классов и аргументы функций именуются по следующей схеме: имя переменной записываеися по основной схеме; добавляется префикс, соответствующий типу переменной (pszIndexName). К публичным полям класса также добавляется префикс m_ (m_pszIndexName).&lt;br /&gt;
&lt;br /&gt;
Префиксы для стандартных типов:&lt;br /&gt;
* [unsigned] int: i, u, n&lt;br /&gt;
* unsigned char, byte: b&lt;br /&gt;
* char: c&lt;br /&gt;
* char*, char[] (в смысле строки): sz&lt;br /&gt;
* [unsigned] short, word: w&lt;br /&gt;
* dword: dw&lt;br /&gt;
* qword: qw&lt;br /&gt;
* любой указатель: p&lt;br /&gt;
&lt;br /&gt;
Для нестандартных типов, префикс выбирается в соответствии с именем типа. &lt;br /&gt;
Длина префикса - от одного до двух символов.&lt;br /&gt;
&lt;br /&gt;
Кроме того:&lt;br /&gt;
# Публичные имена следует давать осмысленными - из имени должно быть ясно, зачем нужна переменная (функция, ...).&lt;br /&gt;
# Предпочтительный диапазон длины имени - от 4 до 20 символов.&lt;br /&gt;
# Предпочтительное количество слов, из которых составлено имя - от 1 до 3.&lt;br /&gt;
# Имена в объявлении класса не должны содержать имя класса. Например, в объявлении класса CFile не должно быть поля m_dwFileSize; следует использовать имя m_dwSize.&lt;br /&gt;
&lt;br /&gt;
=== Правила оформления операторов ===&lt;br /&gt;
&lt;br /&gt;
Для оформления операторов применяются следующие правила:&lt;br /&gt;
&lt;br /&gt;
# Каждому оператору выделяется новая строка.&lt;br /&gt;
# Круглые скобки не выделяются пробелами.&lt;br /&gt;
# Максимальная длина строки - 80 символов. Если требуется больше, остаток оператора переносится на следующую строку, к нему (остатку) добавляется дополнительный отступ.&lt;br /&gt;
# Если тело оператора if или цикла состоит из одного оператора, операторные скобки не ставятся, а оператор записывается с новой строки с дополнительным отступом.&lt;br /&gt;
# На использование пробелов ограничений не накладывается.&lt;br /&gt;
&lt;br /&gt;
=== Запрещенные конструкции ===&lt;br /&gt;
&lt;br /&gt;
Запрещается использование оператора goto. Единственное исключение - выход из циклов с несколькими уровнями вложенности.&lt;br /&gt;
&lt;br /&gt;
Конструкцию do { ... } while(...); крайне не рекомендуется использовать, особенно если тело цикла больше 10 строк.&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/Deptown_Programming_Contest_(DPC)</id>
		<title>Deptown Programming Contest (DPC)</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/Deptown_Programming_Contest_(DPC)"/>
				<updated>2009-05-17T21:23:36Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* Текущее положение дел */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Здравствуй Гость! Ты попал на страничку программерского соревнования в рамках проекта Диптаун =)&lt;br /&gt;
&lt;br /&gt;
DPC это соревнование, участие в котором принимают роботы, находящиеся в виртуальном пространстве диптауна. Управляет роботом программа, написанная на языке [[K++]].&lt;br /&gt;
&lt;br /&gt;
Идея соревнования была заимствована из проекта [http://robocode.sourceforge.net/ Robocode] и адаптирована под текущие реалии и специфику платформы Диптаун. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Для чего это нужно? ==&lt;br /&gt;
&lt;br /&gt;
Если говорить откровенно, то мы еще сами не знаем зачем все это и что из этого может получиться :)&lt;br /&gt;
&lt;br /&gt;
Но на самом деле, у DPC целей много. Во-первых, популяризация самого проекта Диптаун и наглядная демонстрация возможностей платформы Диптауна. Во-вторых, это отличный способ изучить язык [[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;
DPC это в первую очередь соревнование мозгов, а потом уже случайностей и прочих факторов. Поэтому, влияние случайностей должно быть сведено к минимуму. Однако убрать их совсем не получится, опять же в силу специфики платформы, да это и не нужно. Впрочем, нельзя исключать и элемент зрелищности, где случай может сыграть свою роль. Поэтому на данный момент у меня есть несколько вариантов игры :)&lt;br /&gt;
&lt;br /&gt;
На данный момент, я их представляю следующим образом: &lt;br /&gt;
&lt;br /&gt;
== Вариант первый: Sumo Challenge ==&lt;br /&gt;
&lt;br /&gt;
[[Изображение:DPC.png|right]]&lt;br /&gt;
В этом варианте соревнований самые простые правила и роботы. Однако это не значит что победить в нем легко. Наоборот, мне кажется что это лучший из вариантов, поскольку все зависит от тактики робота и качества программы. &lt;br /&gt;
&lt;br /&gt;
=== Арена ===&lt;br /&gt;
&lt;br /&gt;
Арена -- это пространство для соревнования. Арена зависит от типа проводимого соревнования. В данном случае это площадка без ограждений, размерами скажем 10 на 10 метров. Сама площадка может висеть над пустотой или просто являться возвыщением. &lt;br /&gt;
&lt;br /&gt;
В определенных местах на нее помещаются два робота соперника. По сингалу роботы начинают движение. Основная задача -- вытолкнуть соперника за пределы площадки, самому оставшись на ней. Роботы полностью идентичны, они состоят из одинаковых компонентов и имеют одинаковые параметры мощности и скорости. Единственное отличие в программе управления. Более умная программа должна учитывать положение соперника и нападать, в то же время стараясь не подставляться под удар.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Роботы ===&lt;br /&gt;
&lt;br /&gt;
Sumo это простейший вид соревнований, соответственно и роботы должны быть простые :) На данный момент планируется 2 вида роботов: четырех колесные и трехколесные. Первый имеет два рулевых колсеса являющиеся так же ведущими (машина с передним приводом), второй -- два ведущих и одно рулевое (трайк).&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;
&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;, будет выигрывать у &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; на арене завершат бой &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;
== Вариант второй -- классическая Robocode ==&lt;br /&gt;
&lt;br /&gt;
Здесь на первое место выходит зрелищность :) Действие происходит на поле, на котором может находиться сразу несколько соперников. Каждый соперник представлен танком, имеющим пушку и радар. По условиям, танки так же идентичны. &lt;br /&gt;
&lt;br /&gt;
На поле боя могут находиться вспомогательные элементы вроде стен или возвышений. Возвышения позволяют стрелять дальше, если въехать на них, стены помогают защищаться от вражеских выстрелов.&lt;br /&gt;
&lt;br /&gt;
Возможных вариантов стратегий здесь еще больше чем в Sumo. Описывать их все не хватит времени, тем более что по этой теме есть масса материалов на  [http://robocode.sourceforge.net/ официальном сайте].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Текущее положение дел ==&lt;br /&gt;
&lt;br /&gt;
--[[Участник:Velaar|Velaar]] 02:56, 18 мая 2009 (NOVST)&lt;br /&gt;
Всех желающих принять участие в реализации проекта просим в [http://ding.deeptown.org Deeptown DING project].&lt;br /&gt;
&lt;br /&gt;
Как только перейдем к этому проекту, появится соотвествующая новость и запись здесь.&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0</id>
		<title>Заглавная страница</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0"/>
				<updated>2009-05-17T19:26:42Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* Информация */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Информация ==&lt;br /&gt;
&lt;br /&gt;
* [[О проекте]]&lt;br /&gt;
* [[Deeptown SDK]]&lt;br /&gt;
* [[Deptown Programming Contest (DPC)]]&lt;br /&gt;
* [[Задачи|Текущие задачи]]&lt;br /&gt;
* [[Bugzilla]]&lt;br /&gt;
* [[Рассылка]]&lt;br /&gt;
* [[Release Notes]]&lt;br /&gt;
* [[Обратная связь]]&lt;br /&gt;
&lt;br /&gt;
== Документация ==&lt;br /&gt;
&lt;br /&gt;
* [[K++]]&lt;br /&gt;
* [[World Engine]]&lt;br /&gt;
* [[Платформа Gide]]&lt;br /&gt;
* [[Стандартная библиотека gide]]&lt;br /&gt;
* [[Туториалы и HOWTO]]&lt;br /&gt;
* [[Building and running from source]]&lt;br /&gt;
* [[Советы и подсказки]]&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/Deptown_Programming_Contest_(DPC)</id>
		<title>Deptown Programming Contest (DPC)</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/Deptown_Programming_Contest_(DPC)"/>
				<updated>2009-05-17T17:36:16Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* Для чего это нужно? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Здравствуй Гость! Ты попал на страничку программерского соревнования в рамках проекта Диптаун =)&lt;br /&gt;
&lt;br /&gt;
DPC это соревнование, участие в котором принимают роботы, находящиеся в виртуальном пространстве диптауна. Управляет роботом программа, написанная на языке [[K++]].&lt;br /&gt;
&lt;br /&gt;
Идея соревнования была заимствована из проекта [http://robocode.sourceforge.net/ Robocode] и адаптирована под текущие реалии и специфику платформы Диптаун. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Для чего это нужно? ==&lt;br /&gt;
&lt;br /&gt;
Если говорить откровенно, то мы еще сами не знаем зачем все это и что из этого может получиться :)&lt;br /&gt;
&lt;br /&gt;
Но на самом деле, у DPC целей много. Во-первых, популяризация самого проекта Диптаун и наглядная демонстрация возможностей платформы Диптауна. Во-вторых, это отличный способ изучить язык [[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;
DPC это в первую очередь соревнование мозгов, а потом уже случайностей и прочих факторов. Поэтому, влияние случайностей должно быть сведено к минимуму. Однако убрать их совсем не получится, опять же в силу специфики платформы, да это и не нужно. Впрочем, нельзя исключать и элемент зрелищности, где случай может сыграть свою роль. Поэтому на данный момент у меня есть несколько вариантов игры :)&lt;br /&gt;
&lt;br /&gt;
На данный момент, я их представляю следующим образом: &lt;br /&gt;
&lt;br /&gt;
== Вариант первый: Sumo Challenge ==&lt;br /&gt;
&lt;br /&gt;
[[Изображение:DPC.png|right]]&lt;br /&gt;
В этом варианте соревнований самые простые правила и роботы. Однако это не значит что победить в нем легко. Наоборот, мне кажется что это лучший из вариантов, поскольку все зависит от тактики робота и качества программы. &lt;br /&gt;
&lt;br /&gt;
=== Арена ===&lt;br /&gt;
&lt;br /&gt;
Арена -- это пространство для соревнования. Арена зависит от типа проводимого соревнования. В данном случае это площадка без ограждений, размерами скажем 10 на 10 метров. Сама площадка может висеть над пустотой или просто являться возвыщением. &lt;br /&gt;
&lt;br /&gt;
В определенных местах на нее помещаются два робота соперника. По сингалу роботы начинают движение. Основная задача -- вытолкнуть соперника за пределы площадки, самому оставшись на ней. Роботы полностью идентичны, они состоят из одинаковых компонентов и имеют одинаковые параметры мощности и скорости. Единственное отличие в программе управления. Более умная программа должна учитывать положение соперника и нападать, в то же время стараясь не подставляться под удар.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Роботы ===&lt;br /&gt;
&lt;br /&gt;
Sumo это простейший вид соревнований, соответственно и роботы должны быть простые :) На данный момент планируется 2 вида роботов: четырех колесные и трехколесные. Первый имеет два рулевых колсеса являющиеся так же ведущими (машина с передним приводом), второй -- два ведущих и одно рулевое (трайк).&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;
&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;, будет выигрывать у &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; на арене завершат бой &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;
== Вариант второй -- классическая Robocode ==&lt;br /&gt;
&lt;br /&gt;
Здесь на первое место выходит зрелищность :) Действие происходит на поле, на котором может находиться сразу несколько соперников. Каждый соперник представлен танком, имеющим пушку и радар. По условиям, танки так же идентичны. &lt;br /&gt;
&lt;br /&gt;
На поле боя могут находиться вспомогательные элементы вроде стен или возвышений. Возвышения позволяют стрелять дальше, если въехать на них, стены помогают защищаться от вражеских выстрелов.&lt;br /&gt;
&lt;br /&gt;
Возможных вариантов стратегий здесь еще больше чем в Sumo. Описывать их все не хватит времени, тем более что по этой теме есть масса материалов на  [http://robocode.sourceforge.net/ официальном сайте].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Текущее положение дел ==&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/Deptown_Programming_Contest_(DPC)</id>
		<title>Deptown Programming Contest (DPC)</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/Deptown_Programming_Contest_(DPC)"/>
				<updated>2009-05-17T17:33:52Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Здравствуй Гость! Ты попал на страничку программерского соревнования в рамках проекта Диптаун =)&lt;br /&gt;
&lt;br /&gt;
DPC это соревнование, участие в котором принимают роботы, находящиеся в виртуальном пространстве диптауна. Управляет роботом программа, написанная на языке [[K++]].&lt;br /&gt;
&lt;br /&gt;
Идея соревнования была заимствована из проекта [http://robocode.sourceforge.net/ Robocode] и адаптирована под текущие реалии и специфику платформы Диптаун. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Для чего это нужно? ==&lt;br /&gt;
&lt;br /&gt;
А если говорить откровенно, то мы еще сами не знаем зачем все это и что из этого может получиться :)&lt;br /&gt;
&lt;br /&gt;
Но на самом деле, у DPC целей много. Во-первых, популяризация самого проекта Диптаун и наглядная демонстрация возможностей платформы Диптауна. Во-вторых, это отличный способ изучить язык [[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;
DPC это в первую очередь соревнование мозгов, а потом уже случайностей и прочих факторов. Поэтому, влияние случайностей должно быть сведено к минимуму. Однако убрать их совсем не получится, опять же в силу специфики платформы, да это и не нужно. Впрочем, нельзя исключать и элемент зрелищности, где случай может сыграть свою роль. Поэтому на данный момент у меня есть несколько вариантов игры :)&lt;br /&gt;
&lt;br /&gt;
На данный момент, я их представляю следующим образом: &lt;br /&gt;
&lt;br /&gt;
== Вариант первый: Sumo Challenge ==&lt;br /&gt;
&lt;br /&gt;
[[Изображение:DPC.png|right]]&lt;br /&gt;
В этом варианте соревнований самые простые правила и роботы. Однако это не значит что победить в нем легко. Наоборот, мне кажется что это лучший из вариантов, поскольку все зависит от тактики робота и качества программы. &lt;br /&gt;
&lt;br /&gt;
=== Арена ===&lt;br /&gt;
&lt;br /&gt;
Арена -- это пространство для соревнования. Арена зависит от типа проводимого соревнования. В данном случае это площадка без ограждений, размерами скажем 10 на 10 метров. Сама площадка может висеть над пустотой или просто являться возвыщением. &lt;br /&gt;
&lt;br /&gt;
В определенных местах на нее помещаются два робота соперника. По сингалу роботы начинают движение. Основная задача -- вытолкнуть соперника за пределы площадки, самому оставшись на ней. Роботы полностью идентичны, они состоят из одинаковых компонентов и имеют одинаковые параметры мощности и скорости. Единственное отличие в программе управления. Более умная программа должна учитывать положение соперника и нападать, в то же время стараясь не подставляться под удар.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Роботы ===&lt;br /&gt;
&lt;br /&gt;
Sumo это простейший вид соревнований, соответственно и роботы должны быть простые :) На данный момент планируется 2 вида роботов: четырех колесные и трехколесные. Первый имеет два рулевых колсеса являющиеся так же ведущими (машина с передним приводом), второй -- два ведущих и одно рулевое (трайк).&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;
&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;, будет выигрывать у &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; на арене завершат бой &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;
== Вариант второй -- классическая Robocode ==&lt;br /&gt;
&lt;br /&gt;
Здесь на первое место выходит зрелищность :) Действие происходит на поле, на котором может находиться сразу несколько соперников. Каждый соперник представлен танком, имеющим пушку и радар. По условиям, танки так же идентичны. &lt;br /&gt;
&lt;br /&gt;
На поле боя могут находиться вспомогательные элементы вроде стен или возвышений. Возвышения позволяют стрелять дальше, если въехать на них, стены помогают защищаться от вражеских выстрелов.&lt;br /&gt;
&lt;br /&gt;
Возможных вариантов стратегий здесь еще больше чем в Sumo. Описывать их все не хватит времени, тем более что по этой теме есть масса материалов на  [http://robocode.sourceforge.net/ официальном сайте].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Текущее положение дел ==&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/Deptown_Programming_Contest_(DPC)</id>
		<title>Deptown Programming Contest (DPC)</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/Deptown_Programming_Contest_(DPC)"/>
				<updated>2009-05-17T17:20:09Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: Новая: Здравствуй Гость! Ты попал на страничку программерского соревнования в рамках проекта Диптаун =)  DPC э...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Здравствуй Гость! Ты попал на страничку программерского соревнования в рамках проекта Диптаун =)&lt;br /&gt;
&lt;br /&gt;
DPC это соревнование, участие в котором принимают роботы, находящиеся в виртуальном пространстве диптауна. Управляет роботом программа, написанная на языке [[K++]].&lt;br /&gt;
&lt;br /&gt;
Идея соревнования была заимствована из проекта [http://robocode.sourceforge.net/ Robocode] и адаптирована под текущие реалии и специфику платформы Диптаун. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Для чего это нужно? ==&lt;br /&gt;
&lt;br /&gt;
А если говорить откровенно, то мы еще сами не знаем зачем все это и что из этого может получиться :)&lt;br /&gt;
&lt;br /&gt;
Но на самом деле, у DPC целей много. Во-первых, популяризация самого проекта Диптаун и наглядная демонстрация возможностей платформы Диптауна. Во-вторых, это отличный способ изучить язык [[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;
DPC это в первую очередь соревнование мозгов, а потом уже случайностей и прочих факторов. Поэтому, влияние случайностей должно быть сведено к минимуму. Однако убрать их совсем не получится, опять же в силу специфики платформы, да это и не нужно. Впрочем, нельзя исключать и элемент зрелищности, где случай может сыграть свою роль. Поэтому на данный момент у меня есть несколько вариантов игры :)&lt;br /&gt;
&lt;br /&gt;
На данный момент, я их представляю следующим образом: &lt;br /&gt;
&lt;br /&gt;
== Вариант первый: Sumo Challenge ==&lt;br /&gt;
&lt;br /&gt;
[[Изображение:DPC.png|right]]&lt;br /&gt;
В этом варианте соревнований самые простые правила и роботы. Однако это не значит что победить в нем легко. Наоборот, мне кажется что это лучший из вариантов, поскольку все зависит от тактики робота и качества программы. &lt;br /&gt;
&lt;br /&gt;
=== Арена ===&lt;br /&gt;
&lt;br /&gt;
Арена -- это пространство для соревнования. Арена зависит от типа проводимого соревнования. В данном случае это площадка без ограждений, размерами скажем 10 на 10 метров. Сама площадка может висеть над пустотой или просто являться возвыщением. &lt;br /&gt;
&lt;br /&gt;
В определенных местах на нее помещаются два робота соперника. По сингалу роботы начинают движение. Основная задача -- вытолкнуть соперника за пределы площадки, самому оставшись на ней. Роботы полностью идентичны, они состоят из одинаковых компонентов и имеют одинаковые параметры мощности и скорости. Единственное отличие в программе управления. Более умная программа должна учитывать положение соперника и нападать, в то же время стараясь не подставляться под удар.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Роботы ===&lt;br /&gt;
&lt;br /&gt;
Sumo это простейший вид соревнований, соответственно и роботы должны быть простые :) На данный момент планируется 2 вида роботов: четырех колесные и трехколесные. Первый имеет два рулевых колсеса являющиеся так же ведущими (машина с передним приводом), второй -- два ведущих и одно рулевое (трайк).&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;
&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;, будет выигрывать у &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; на арене завершат бой &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>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%A4%D0%B0%D0%B9%D0%BB:DPC.png</id>
		<title>Файл:DPC.png</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%A4%D0%B0%D0%B9%D0%BB:DPC.png"/>
				<updated>2009-05-17T16:44:26Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: Площадка для Sumo Challenge&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Площадка для Sumo Challenge&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B8</id>
		<title>Задачи</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B8"/>
				<updated>2009-05-17T15:36:39Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;В данном разделе мы публикуем текущий список задач Deeptown SDK. Большая часть задач — это разработка тех или иных модулей/программ на языке [[K++]]. Некоторые задачи предполагают реализацию на C++.&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;
Однако будьте готовы к тому, что мы не примем некачественный код. Мы следим за качеством нашей системы. Перед тем, как приступать, пожалуйста, ознакомьтесь с [[Правила оформления кода|правилами оформления кода]].&lt;br /&gt;
&lt;br /&gt;
=== Оформление данного раздела ===&lt;br /&gt;
&lt;br /&gt;
В данном разделе задачи разбиты на несколько категорий. Каждая задача — это подраздел в своей категории. Простые задачи описываются прямо в тексте; для более сложных даются ссылки на отдельные страницы описаний. Новые задачи всегда добавляются наверх своего раздела.&lt;br /&gt;
&lt;br /&gt;
Для каждой задачи приводится следующая служебная информация:&lt;br /&gt;
* '''сложность''' — уровень сложности задачи: простая, средняя, сложная&lt;br /&gt;
* '''технологии''' — список технологий (языков, библиотек, etc), которые потребуются для выполнения задачи&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;
В информации об исполнителе должно указываться какое-нибудь средство связи с Вами: e-mail, ICQ или jabber. Вы можете написать свои контактные данные в &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;
В поле &amp;quot;срок&amp;quot; следует вписать предполагаемую дату завершения. Максимальный срок, который Вы можете установить — это текущая дата плюс 2 недели, если иное не указано в примечаниях к задаче.&lt;br /&gt;
&lt;br /&gt;
Процедура обнаружения &amp;quot;призраков&amp;quot; такова. Когда срок исполнения выходит, мы связываемся с Вами по указанным контактным данным, и узнаем статус задачи/договариваемся о дальнейшем. Если связаться не удается в течение недели — мы убираем информацию об исполнителе, открывая таким образом задачу для других.&lt;br /&gt;
&lt;br /&gt;
=== Порядок приема задач ===&lt;br /&gt;
&lt;br /&gt;
На данный момент у нас нет (публичного) централизованного обменника исходными кодами. Поэтому, высылайте свои труды в архиве на адрес developers (гав) deeptown.org. Либо Вы можете выложить их куда-нибудь в интернет, и выслать ссылку по этому адресу.&lt;br /&gt;
&lt;br /&gt;
=== Условия лицензирования ===&lt;br /&gt;
&lt;br /&gt;
Мы можем принять Ваш код только в том случае, если Вы передаете его нам на условиях свободной лицензии. Пожалуйста, вложите текст лицензии в архив с кодом. Мы не будем принимать архивы без текстов лицензии, поскольку это может грозить нам судебными исками (исключение — только для наших разработчиков, которые подписали с нами договор).&lt;br /&gt;
&lt;br /&gt;
Предпочтительной является [http://www.opensource.org/licenses/mit-license.php лицензия MIT], но Вы можете взять другую свободную лицензию или даже написать свою. Однако имейте ввиду: мы ответственно подходим к лицензированию кода, поэтому без внимания мы это не оставим.&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;span style=&amp;quot;color: white; background-color: #00FF00;&amp;quot;&amp;gt;· раз плюнуть ·&amp;lt;/span&amp;gt;&lt;br /&gt;
: &amp;lt;span style=&amp;quot;color: white; background-color: #008000;&amp;quot;&amp;gt;· низкая ·&amp;lt;/span&amp;gt;&lt;br /&gt;
: &amp;lt;span style=&amp;quot;color: white; background-color: #FFCC00;&amp;quot;&amp;gt;· средняя ·&amp;lt;/span&amp;gt;&lt;br /&gt;
: &amp;lt;span style=&amp;quot;color: white; background-color: #FF8000;&amp;quot;&amp;gt;· выше среднего ·&amp;lt;/span&amp;gt;&lt;br /&gt;
: &amp;lt;span style=&amp;quot;color: white; background-color: #DD0000;&amp;quot;&amp;gt;· высокая ·&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Категории востребованности (приоритет):&lt;br /&gt;
: &amp;lt;span style=&amp;quot;color: white; background-color: #A0A0A0;&amp;quot;&amp;gt;· может подождать ·&amp;lt;/span&amp;gt;&lt;br /&gt;
: &amp;lt;span style=&amp;quot;color: white; background-color: #808080;&amp;quot;&amp;gt;· низкий ·&amp;lt;/span&amp;gt;&lt;br /&gt;
: &amp;lt;span style=&amp;quot;color: white; background-color: #FFCC00;&amp;quot;&amp;gt;· средний ·&amp;lt;/span&amp;gt;&lt;br /&gt;
: &amp;lt;span style=&amp;quot;color: white; background-color: #FF8000;&amp;quot;&amp;gt;· выше среднего ·&amp;lt;/span&amp;gt;&lt;br /&gt;
: &amp;lt;span style=&amp;quot;color: white; background-color: #DD0000;&amp;quot;&amp;gt;· высокий ·&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Операторы DSH ==&lt;br /&gt;
&lt;br /&gt;
По сути это команды, но играют роль структурных элементов шеллового языка программирования. Необходимо реализовать команды: true, false, test, if, switch, for, foreach.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* '''Сложность''': &amp;lt;span style=&amp;quot;color: white; background-color: #008000;&amp;quot;&amp;gt;· низкая ·&amp;lt;/span&amp;gt;  '''Приоритет''': &amp;lt;span style=&amp;quot;color: white; background-color: #DD0000;&amp;quot;&amp;gt;· высокий ·&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Технологии''': &lt;br /&gt;
* '''Автор''': --[[Участник:Korvin|Korvin]] 07:38, 18 июня 2008 (EDT)&lt;br /&gt;
* '''Примечания''': &lt;br /&gt;
* '''Исполнитель''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не назначен (вакансия)&amp;lt;/span&amp;gt;&lt;br /&gt;
* '''Срок''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не установлен&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Базовые команды оболочки DSH ==&lt;br /&gt;
&lt;br /&gt;
Ниже приведены команды, которые требуется реализовать для нормального функционирования командной оболочки Диптауна (DSH). Дабы не изобретать велосипед, было решено делать команды максимально похожими на их UNIX аналоги. Однако, следует помнить, что при реализации команд, надо учитывать специфику диптауна и ориентироваться на максимальное юзабилити а не стопроцентное соответствие UNIX. Короче говоря, не надо стараться реализовать полный клон команды, со всеми &amp;quot;наворотами&amp;quot; — достаточно только базовых возможностей, которые гарантированно понадобятся и будут полезны.&lt;br /&gt;
&lt;br /&gt;
'''Примечание''': Все без исключения команды должны поддерживать следующие ключи:&lt;br /&gt;
;'''--version''': Вывод информации о версии программы и ее авторе.&lt;br /&gt;
;'''--help''': Вывод краткой справки по использованию команды. Может выводиться так же при отсутствии какого либо ввода со стороны пользователя (вызов команды без параметров), если это не противоречит логике работы команды.&lt;br /&gt;
;'''--''': Индикатор окончания списка параметров. Если в строке параметров встречается данный символ, это означает что дальнейшая информация уже не является параметрами. Например, команды &lt;br /&gt;
::&amp;lt;tt&amp;gt;deep$ ls -l&amp;lt;/tt&amp;gt;&lt;br /&gt;
и&lt;br /&gt;
::&amp;lt;tt&amp;gt;deep$ ls -- -l&amp;lt;/tt&amp;gt;&lt;br /&gt;
:имеют различный смысл. В первом случае вызывается расширенный список файлов текущей директории, тогда как во втором делается попытка отобразить содержимое директории с именем &amp;quot;-l&amp;quot;.&lt;br /&gt;
;'''-''': Отдельный дефиз может использоваться всесто имени файла для указания того, что данные требуется получать из стандартного устройства ввода. А вывод — соответственно направлять в устройство вывода. Конкретное поведение зависит от используемой команды. Таким образом, следующие команды являются эквивалентами:&lt;br /&gt;
::&amp;lt;tt&amp;gt;deep$ cat &amp;lt;/tt&amp;gt;&lt;br /&gt;
::&amp;lt;tt&amp;gt;deep$ cat - &amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ls  === &lt;br /&gt;
&lt;br /&gt;
Команда ls (от англ. ''list'' — список) выводит в терминал содержимое некоторой директории. Формат списка, а так же исследуемая директория, задются с помощью соответствующих ключей. &lt;br /&gt;
&lt;br /&gt;
* '''Сложность''': &amp;lt;span style=&amp;quot;color: white; background-color: #008000;&amp;quot;&amp;gt;· низкая ·&amp;lt;/span&amp;gt;  '''Приоритет''': &amp;lt;span style=&amp;quot;color: white; background-color: #DD0000;&amp;quot;&amp;gt;· высокий ·&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Технологии''': [[DISS]], [[регулярные выражения]]&lt;br /&gt;
* '''Автор''': --[[Участник:Korvin|Korvin]] 07:38, 18 июня 2008 (EDT)&lt;br /&gt;
* '''Примечания''': Описание UNIX аналога команды можно найти [http://www.opennet.ru/man.shtml?topic=ls здесь].&lt;br /&gt;
* '''Исполнитель''': [http://ding.deeptown.org Deeptown DING project]&lt;br /&gt;
* '''Срок''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не установлен&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;s&amp;gt;cp&amp;lt;/s&amp;gt;  === &lt;br /&gt;
&lt;br /&gt;
Команда cp (от англ. ''copy'' — копировать) производит копирование содержимого указанного каталога в новый каталог. &lt;br /&gt;
&lt;br /&gt;
* '''Сложность''': &amp;lt;span style=&amp;quot;color: white; background-color: #008000;&amp;quot;&amp;gt;· низкая ·&amp;lt;/span&amp;gt;  '''Приоритет''': &amp;lt;span style=&amp;quot;color: white; background-color: #DD0000;&amp;quot;&amp;gt;· высокий ·&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Технологии''': [[DISS]]&lt;br /&gt;
* '''Автор''': --[[Участник:Korvin|Korvin]] 08:24, 18 июня 2008 (EDT)&lt;br /&gt;
* '''Примечания''': Описание UNIX аналога команды можно найти [http://www.opennet.ru/man.shtml?topic=cp здесь].&lt;br /&gt;
* '''Исполнитель''': [http://ding.deeptown.org Deeptown DING project]&lt;br /&gt;
* '''Срок''': реализовано&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== mv  === &lt;br /&gt;
&lt;br /&gt;
Команда mv (от англ. ''move'' — переместить) производит перемещение содержимого указанного каталога в новый каталог, либо переименовывает файлы (каталоги). &lt;br /&gt;
&lt;br /&gt;
* '''Сложность''': &amp;lt;span style=&amp;quot;color: white; background-color: #008000;&amp;quot;&amp;gt;· низкая ·&amp;lt;/span&amp;gt;  '''Приоритет''': &amp;lt;span style=&amp;quot;color: white; background-color: #DD0000;&amp;quot;&amp;gt;· высокий ·&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Технологии''': [[DISS]]&lt;br /&gt;
* '''Автор''': --[[Участник:Korvin|Korvin]] 08:24, 18 июня 2008 (EDT)&lt;br /&gt;
* '''Примечания''': Описание UNIX аналога команды можно найти [http://www.opennet.ru/man.shtml?topic=mv здесь].&lt;br /&gt;
* '''Исполнитель''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не назначен (вакансия)&amp;lt;/span&amp;gt;&lt;br /&gt;
* '''Срок''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не установлен&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;s&amp;gt;rm&amp;lt;/s&amp;gt;  === &lt;br /&gt;
&lt;br /&gt;
Команда rm (от англ. ''remove'' — удалить) удаляет файл, либо каталог. &lt;br /&gt;
&lt;br /&gt;
* '''Сложность''': &amp;lt;span style=&amp;quot;color: white; background-color: #008000;&amp;quot;&amp;gt;· низкая ·&amp;lt;/span&amp;gt;  '''Приоритет''': &amp;lt;span style=&amp;quot;color: white; background-color: #DD0000;&amp;quot;&amp;gt;· высокий ·&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Технологии''': [[DISS]]&lt;br /&gt;
* '''Автор''': --[[Участник:Korvin|Korvin]] 08:24, 18 июня 2008 (EDT)&lt;br /&gt;
* '''Примечания''': Описание UNIX аналога команды можно найти [http://www.opennet.ru/man.shtml?topic=rm здесь].&lt;br /&gt;
* '''Исполнитель''': [http://ding.deeptown.org Deeptown DING project]&lt;br /&gt;
* '''Срок''': реализовано&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;s&amp;gt;touch&amp;lt;/s&amp;gt;  === &lt;br /&gt;
&lt;br /&gt;
Команда touch (от англ. ''touch'' — потрогать) создает пустой файл с указанным именем, либо изменяет время доступа существующего файла. &lt;br /&gt;
&lt;br /&gt;
* '''Сложность''': &amp;lt;span style=&amp;quot;color: white; background-color: #00FF00;&amp;quot;&amp;gt;· раз плюнуть ·&amp;lt;/span&amp;gt;  '''Приоритет''': &amp;lt;span style=&amp;quot;color: white; background-color: #DD0000;&amp;quot;&amp;gt;· высокий ·&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Технологии''': [[DISS]]&lt;br /&gt;
* '''Автор''': --[[Участник:Korvin|Korvin]] 08:24, 18 июня 2008 (EDT)&lt;br /&gt;
* '''Примечания''': Описание UNIX аналога команды можно найти [http://www.opennet.ru/man.shtml?topic=touch здесь].&lt;br /&gt;
* '''Исполнитель''': [http://ding.deeptown.org Deeptown DING project]&lt;br /&gt;
* '''Срок''': реализовано&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== mkdir  === &lt;br /&gt;
&lt;br /&gt;
Команда mkdir (от англ. ''make directory'') создает директорию с указанным именем. &lt;br /&gt;
&lt;br /&gt;
* '''Сложность''': &amp;lt;span style=&amp;quot;color: white; background-color: #00FF00;&amp;quot;&amp;gt;· раз плюнуть ·&amp;lt;/span&amp;gt;  '''Приоритет''': &amp;lt;span style=&amp;quot;color: white; background-color: #DD0000;&amp;quot;&amp;gt;· высокий ·&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Технологии''': [[DISS]]&lt;br /&gt;
* '''Автор''': --[[Участник:Korvin|Korvin]] 08:24, 18 июня 2008 (EDT)&lt;br /&gt;
* '''Примечания''': Описание UNIX аналога команды можно найти [http://www.opennet.ru/man.shtml?topic=mkdir здесь].&lt;br /&gt;
* '''Исполнитель''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;Deeptown DING project&amp;lt;/span&amp;gt;&lt;br /&gt;
* '''Срок''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не установлен&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== grep  === &lt;br /&gt;
&lt;br /&gt;
Команда grep производит фильтрацию своего входного потока и выдает результат в выходной поток. Следует иметь в виду, что реализация PCRE (используемая в К++) синтаксически отличается от канонической UNIX. Основная задача — выборка интересующих строк из входного потока.&lt;br /&gt;
&lt;br /&gt;
* '''Сложность''': &amp;lt;span style=&amp;quot;color: white; background-color: #008000;&amp;quot;&amp;gt;· низкая ·&amp;lt;/span&amp;gt;  '''Приоритет''': &amp;lt;span style=&amp;quot;color: white; background-color: #FF8000;&amp;quot;&amp;gt;· выше среднего ·&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Технологии''': [[DISS]], [[регулярные выражения]]&lt;br /&gt;
* '''Автор''': --[[Участник:Korvin|Korvin]] 08:24, 18 июня 2008 (EDT)&lt;br /&gt;
* '''Примечания''': Описание UNIX аналога команды можно найти [http://www.opennet.ru/man.shtml?topic=grep здесь].&lt;br /&gt;
* '''Исполнитель''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не назначен (вакансия)&amp;lt;/span&amp;gt;&lt;br /&gt;
* '''Срок''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не установлен&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== sed  === &lt;br /&gt;
&lt;br /&gt;
Команда sed (от англ. ''stream editor'' — редактор потоков) производит фильтрацию своего входного потока и выдает результат в выходной поток. Следует иметь в виду, что реализация PCRE (используемая в К++) синтаксически отличается от канонической UNIX. Основная задача — преобразование данных по шаблону.&lt;br /&gt;
&lt;br /&gt;
* '''Сложность''': &amp;lt;span style=&amp;quot;color: white; background-color: #008000;&amp;quot;&amp;gt;· низкая ·&amp;lt;/span&amp;gt;  '''Приоритет''': &amp;lt;span style=&amp;quot;color: white; background-color: #808080;&amp;quot;&amp;gt;· низкий ·&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Технологии''': [[DISS]], [[регулярные выражения]]&lt;br /&gt;
* '''Автор''': --[[Участник:Korvin|Korvin]] 08:24, 18 июня 2008 (EDT)&lt;br /&gt;
* '''Примечания''': Описание UNIX аналога команды можно найти [http://www.opennet.ru/man.shtml?topic=sed здесь].&lt;br /&gt;
* '''Исполнитель''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не назначен (вакансия)&amp;lt;/span&amp;gt;&lt;br /&gt;
* '''Срок''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не установлен&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== wc  === &lt;br /&gt;
&lt;br /&gt;
Команда wc (от англ. ''word counter'' — счетчик слов) производит подсчет количества структурных элементов в своем входном потоке и выдает результат в выходной поток. В качестве таких элементов могут выступать символы (ключ &amp;lt;tt&amp;gt;-c&amp;lt;/tt&amp;gt;), строки (ключ &amp;lt;tt&amp;gt;-l&amp;lt;/tt&amp;gt;) и др. Таким образом, простейший способ подсчета количества строк в файле может выглядеть так:&lt;br /&gt;
:&amp;lt;tt&amp;gt;deep$ cat myfile | wc -l&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* '''Сложность''': &amp;lt;span style=&amp;quot;color: white; background-color: #008000;&amp;quot;&amp;gt;· низкая ·&amp;lt;/span&amp;gt;  '''Приоритет''': &amp;lt;span style=&amp;quot;color: white; background-color: #808080;&amp;quot;&amp;gt;· низкий ·&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Технологии''': [[DISS]], [[регулярные выражения]]&lt;br /&gt;
* '''Автор''': --[[Участник:Korvin|Korvin]] 08:24, 18 июня 2008 (EDT)&lt;br /&gt;
* '''Примечания''': Описание UNIX аналога команды можно найти [http://www.opennet.ru/man.shtml?topic=wc здесь].&lt;br /&gt;
* '''Исполнитель''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не назначен (вакансия)&amp;lt;/span&amp;gt;&lt;br /&gt;
* '''Срок''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не установлен&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== nl  === &lt;br /&gt;
&lt;br /&gt;
Команда nl (от англ. ''numbered lines'' — пронумерованные строки) записывает в стандартный поток вывода данные из своего стандартного потока ввода, предворяя их номерами строк. Может использоваться для формирования листингов программ, составления отчетов и др.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* '''Сложность''': &amp;lt;span style=&amp;quot;color: white; background-color: #00FF00;&amp;quot;&amp;gt;· раз плюнуть ·&amp;lt;/span&amp;gt;  '''Приоритет''': &amp;lt;span style=&amp;quot;color: white; background-color: #808080;&amp;quot;&amp;gt;· низкий ·&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Технологии''': &lt;br /&gt;
* '''Автор''': --[[Участник:Korvin|Korvin]] 08:24, 18 июня 2008 (EDT)&lt;br /&gt;
* '''Примечания''': Описание UNIX аналога команды можно найти [http://www.opennet.ru/man.shtml?topic=nl здесь].&lt;br /&gt;
* '''Исполнитель''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не назначен (вакансия)&amp;lt;/span&amp;gt;&lt;br /&gt;
* '''Срок''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не установлен&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== sort  === &lt;br /&gt;
&lt;br /&gt;
Команда sort производит сортировку данных из своего входного потока и выдает результат в выходной поток. &lt;br /&gt;
&lt;br /&gt;
* '''Сложность''': &amp;lt;span style=&amp;quot;color: white; background-color: #008000;&amp;quot;&amp;gt;· низкая ·&amp;lt;/span&amp;gt;  '''Приоритет''': &amp;lt;span style=&amp;quot;color: white; background-color: #808080;&amp;quot;&amp;gt;· низкий ·&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Технологии''': [[DISS]]&lt;br /&gt;
* '''Автор''': --[[Участник:Korvin|Korvin]] 08:24, 18 июня 2008 (EDT)&lt;br /&gt;
* '''Примечания''': Описание UNIX аналога команды можно найти [http://www.opennet.ru/man.shtml?topic=sort здесь].&lt;br /&gt;
* '''Исполнитель''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не назначен (вакансия)&amp;lt;/span&amp;gt;&lt;br /&gt;
* '''Срок''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не установлен&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== head  === &lt;br /&gt;
&lt;br /&gt;
Команда head возвращает первые N строк из своего входного потока. &lt;br /&gt;
&lt;br /&gt;
* '''Сложность''': &amp;lt;span style=&amp;quot;color: white; background-color: #00FF00;&amp;quot;&amp;gt;· раз плюнуть ·&amp;lt;/span&amp;gt;  '''Приоритет''': &amp;lt;span style=&amp;quot;color: white; background-color: #808080;&amp;quot;&amp;gt;· низкий ·&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Технологии''': [[DISS]]&lt;br /&gt;
* '''Автор''': --[[Участник:Korvin|Korvin]] 08:24, 18 июня 2008 (EDT)&lt;br /&gt;
* '''Примечания''': Описание UNIX аналога команды можно найти [http://www.opennet.ru/man.shtml?topic=head здесь].&lt;br /&gt;
* '''Исполнитель''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не назначен (вакансия)&amp;lt;/span&amp;gt;&lt;br /&gt;
* '''Срок''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не установлен&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== tail  === &lt;br /&gt;
&lt;br /&gt;
Команда head возвращает последние N строк из своего входного потока. &lt;br /&gt;
&lt;br /&gt;
* '''Сложность''': &amp;lt;span style=&amp;quot;color: white; background-color: #00FF00;&amp;quot;&amp;gt;· раз плюнуть ·&amp;lt;/span&amp;gt;  '''Приоритет''': &amp;lt;span style=&amp;quot;color: white; background-color: #808080;&amp;quot;&amp;gt;· низкий ·&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Технологии''': [[DISS]]&lt;br /&gt;
* '''Автор''': --[[Участник:Korvin|Korvin]] 08:24, 18 июня 2008 (EDT)&lt;br /&gt;
* '''Примечания''': Описание UNIX аналога команды можно найти [http://www.opennet.ru/man.shtml?topic=tail здесь].&lt;br /&gt;
* '''Исполнитель''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не назначен (вакансия)&amp;lt;/span&amp;gt;&lt;br /&gt;
* '''Срок''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не установлен&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== more  === &lt;br /&gt;
&lt;br /&gt;
Команда more выводит данные из своего входного потока порциями по N строк. Используется для постепенного отображения содержимого буфера в консоль (так, чтобы пользователь успел все прочитать).&lt;br /&gt;
&lt;br /&gt;
* '''Сложность''': &amp;lt;span style=&amp;quot;color: white; background-color: #00FF00;&amp;quot;&amp;gt;· раз плюнуть ·&amp;lt;/span&amp;gt;  '''Приоритет''': &amp;lt;span style=&amp;quot;color: white; background-color: #DD0000;&amp;quot;&amp;gt;· высокий ·&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Технологии''': [[DISS]]&lt;br /&gt;
* '''Автор''': --[[Участник:Korvin|Korvin]] 08:24, 18 июня 2008 (EDT)&lt;br /&gt;
* '''Примечания''': Описание UNIX аналога команды можно найти [http://www.opennet.ru/man.shtml?topic=more здесь].&lt;br /&gt;
* '''Исполнитель''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не назначен (вакансия)&amp;lt;/span&amp;gt;&lt;br /&gt;
* '''Срок''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не установлен&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== mount  === &lt;br /&gt;
&lt;br /&gt;
Команда mount используется для привязки носителей данных к файловой системе Диптауна. Принципы ее работы несколько отличаются от UNIX аналога, поэтому документация не дается. Для получения информации, необходимо [[Обратная связь|связаться с разработчиками]].&lt;br /&gt;
&lt;br /&gt;
* '''Сложность''': &amp;lt;span style=&amp;quot;color: white; background-color: #008000;&amp;quot;&amp;gt;· низкая ·&amp;lt;/span&amp;gt;  '''Приоритет''': &amp;lt;span style=&amp;quot;color: white; background-color: #FF8000;&amp;quot;&amp;gt;· выше среднего ·&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Технологии''': [[DISS]]&lt;br /&gt;
* '''Автор''': --[[Участник:Korvin|Korvin]] 08:24, 18 июня 2008 (EDT)&lt;br /&gt;
* '''Примечания''':&lt;br /&gt;
* '''Исполнитель''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не назначен (вакансия)&amp;lt;/span&amp;gt;&lt;br /&gt;
* '''Срок''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не установлен&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== chmod  === &lt;br /&gt;
&lt;br /&gt;
Команда chmod используется для изменения прав доступа к файлам в файловой системе Диптауна. Принципы ее работы несколько отличаются от UNIX аналога, поэтому документация не дается. Для получения информации, необходимо [[Обратная связь|связаться с разработчиками]].&lt;br /&gt;
&lt;br /&gt;
* '''Сложность''': &amp;lt;span style=&amp;quot;color: white; background-color: #008000;&amp;quot;&amp;gt;· низкая ·&amp;lt;/span&amp;gt;  '''Приоритет''': &amp;lt;span style=&amp;quot;color: white; background-color: #FF8000;&amp;quot;&amp;gt;· выше среднего ·&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Технологии''': [[DISS]]&lt;br /&gt;
* '''Автор''': --[[Участник:Korvin|Korvin]] 08:24, 18 июня 2008 (EDT)&lt;br /&gt;
* '''Примечания''':&lt;br /&gt;
* '''Исполнитель''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не назначен (вакансия)&amp;lt;/span&amp;gt;&lt;br /&gt;
* '''Срок''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не установлен&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== chown  === &lt;br /&gt;
&lt;br /&gt;
Команда chown используется для изменения владельца и группы файлов в файловой системе Диптауна. &lt;br /&gt;
&lt;br /&gt;
* '''Сложность''': &amp;lt;span style=&amp;quot;color: white; background-color: #008000;&amp;quot;&amp;gt;· низкая ·&amp;lt;/span&amp;gt;  '''Приоритет''': &amp;lt;span style=&amp;quot;color: white; background-color: #FFCC00;&amp;quot;&amp;gt;· средний ·&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Технологии''': [[DISS]]&lt;br /&gt;
* '''Автор''': --[[Участник:Korvin|Korvin]] 08:24, 18 июня 2008 (EDT)&lt;br /&gt;
* '''Примечания''': Описание UNIX аналога команды можно найти [http://www.opennet.ru/man.shtml?topic=chown здесь].&lt;br /&gt;
* '''Исполнитель''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не назначен (вакансия)&amp;lt;/span&amp;gt;&lt;br /&gt;
* '''Срок''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не установлен&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== chattr  === &lt;br /&gt;
&lt;br /&gt;
Команда chattr используется для изменения атрибутов файлов (в основном метаинформации) в файловой системе Диптауна. Принципы ее работы несколько отличаются от UNIX аналога, поэтому документация не дается. Для получения информации, необходимо [[Обратная связь|связаться с разработчиками]].&lt;br /&gt;
&lt;br /&gt;
* '''Сложность''': &amp;lt;span style=&amp;quot;color: white; background-color: #008000;&amp;quot;&amp;gt;· низкая ·&amp;lt;/span&amp;gt;  '''Приоритет''': &amp;lt;span style=&amp;quot;color: white; background-color: #FFCC00;&amp;quot;&amp;gt;· средний ·&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Технологии''': [[DISS]]&lt;br /&gt;
* '''Автор''': --[[Участник:Korvin|Korvin]] 08:24, 18 июня 2008 (EDT)&lt;br /&gt;
* '''Примечания''': &lt;br /&gt;
* '''Исполнитель''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не назначен (вакансия)&amp;lt;/span&amp;gt;&lt;br /&gt;
* '''Срок''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не установлен&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== su  === &lt;br /&gt;
&lt;br /&gt;
Команда su (от англ. ''switch user'' — переключить пользователя) используется для запуска подоболочки от имени другого пользователя.&lt;br /&gt;
&lt;br /&gt;
* '''Сложность''': &amp;lt;span style=&amp;quot;color: white; background-color: #008000;&amp;quot;&amp;gt;· низкая ·&amp;lt;/span&amp;gt;  '''Приоритет''': &amp;lt;span style=&amp;quot;color: white; background-color: #808080;&amp;quot;&amp;gt;· низкий ·&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Технологии''': [[UserDB]], [[DSH]]&lt;br /&gt;
* '''Автор''': --[[Участник:Korvin|Korvin]] 08:24, 18 июня 2008 (EDT)&lt;br /&gt;
* '''Примечания''': Описание UNIX аналога команды можно найти [http://www.opennet.ru/man.shtml?topic=su здесь].&lt;br /&gt;
* '''Исполнитель''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не назначен (вакансия)&amp;lt;/span&amp;gt;&lt;br /&gt;
* '''Срок''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не установлен&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== sudo  === &lt;br /&gt;
&lt;br /&gt;
Команда sudo позволяет выполнить команду от имени другого пользователя.&lt;br /&gt;
&lt;br /&gt;
* '''Сложность''': &amp;lt;span style=&amp;quot;color: white; background-color: #008000;&amp;quot;&amp;gt;· низкая ·&amp;lt;/span&amp;gt;  '''Приоритет''': &amp;lt;span style=&amp;quot;color: white; background-color: #808080;&amp;quot;&amp;gt;· низкий ·&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Технологии''': [[UserDB]], [[DSH]]&lt;br /&gt;
* '''Автор''': --[[Участник:Korvin|Korvin]] 08:24, 18 июня 2008 (EDT)&lt;br /&gt;
* '''Примечания''': Описание UNIX аналога команды можно найти [http://www.opennet.ru/man.shtml?topic=sudo здесь].&lt;br /&gt;
* '''Исполнитель''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не назначен (вакансия)&amp;lt;/span&amp;gt;&lt;br /&gt;
* '''Срок''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не установлен&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== passwd  === &lt;br /&gt;
&lt;br /&gt;
Команда passwd позволяет сменить пароль пользователя.&lt;br /&gt;
&lt;br /&gt;
* '''Сложность''': &amp;lt;span style=&amp;quot;color: white; background-color: #008000;&amp;quot;&amp;gt;· низкая ·&amp;lt;/span&amp;gt;  '''Приоритет''': &amp;lt;span style=&amp;quot;color: white; background-color: #FFCC00;&amp;quot;&amp;gt;· средний ·&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Технологии''': [[UserDB]], [[DSH]]&lt;br /&gt;
* '''Автор''': --[[Участник:Korvin|Korvin]] 08:24, 18 июня 2008 (EDT)&lt;br /&gt;
* '''Примечания''': Описание UNIX аналога команды можно найти [http://www.opennet.ru/man.shtml?topic=passwd здесь].&lt;br /&gt;
* '''Исполнитель''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не назначен (вакансия)&amp;lt;/span&amp;gt;&lt;br /&gt;
* '''Срок''': &amp;lt;span style=&amp;quot;color: #808080;&amp;quot;&amp;gt;не установлен&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Стандартный интерфейс SQL ==&lt;br /&gt;
== Универсальный HTTP клиент ==&lt;br /&gt;
== Универсальный HTTP сервер ==&lt;br /&gt;
== Репозиторий медиаданных ==&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/K%2B%2B</id>
		<title>K++</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/K%2B%2B"/>
				<updated>2009-04-22T09:11:20Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
[[Изображение:head.png]]&lt;br /&gt;
&lt;br /&gt;
По мере разработки платформы Диптаун, нами была осознана необходимость создания удобного и универсального средства для управления платформой. Изначально, мы хотели реализовать ее так, чтобы платформа была максимально гибкой и расширяемой; чтобы она позволяла вносить изменения практически в любую ее часть без необходимости пересмотра и переработки системы в целом. Неотъемлемой частью существующей реализации является [[виртуальная машина Gide]], которая берет на себя большую часть задач по управлению различными частями платформы и организации их взаимодействия. Gide применяется практически во всех задачах: начиная от генерации процедурных текстур и до пользовательского интерфейса; от управления аватарами и до программирования объектов виртуального пространства.&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;
* © Дмитрий Кашицын, 2007-2009&lt;br /&gt;
* © Дмитрий Роот, 2007-2009  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Введение ==&lt;br /&gt;
&lt;br /&gt;
# [[Предисловие]]&lt;br /&gt;
## [[Предисловие#Роль K++ в проекте Диптаун|Роль K++ в проекте Диптаун]]&lt;br /&gt;
## [[Предисловие#Почему именно K++?|Почему именно K++?]]&lt;br /&gt;
## [[Предисловие#Для кого эта книга|Для кого эта книга]]&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;
## [[Введение, или краткий обзор#Использование блоков|Использование блоков]]&lt;br /&gt;
## [[Введение, или краткий обзор#Расширение классов|Расширение классов]]&lt;br /&gt;
# [[Переменные]] &lt;br /&gt;
## [[Переменные#Понятие переменной, тип переменной|Понятие переменной, тип переменной]]&lt;br /&gt;
## [[Переменные#Статическая типизация на примере C++|Статическая типизация на примере C++]]&lt;br /&gt;
## [[Переменные#Динамическая типизация на примере Ruby|Динамическая типизация на примере Ruby]]&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;
## [[Классы и объекты#Понятие объекта|Понятие объекта]]&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;
### [[Функции#Типизация аргументов|Типизация аргументов]]&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;
### [[Основные синтаксические конструкции#Оператор if|Оператор if]]&lt;br /&gt;
### [[Основные синтаксические конструкции#Оператор if-else|Оператор if-else]]&lt;br /&gt;
### [[Основные синтаксические конструкции#Оператор if-elsif-else|Оператор if-elsif-else]]&lt;br /&gt;
### [[Основные синтаксические конструкции#Постфиксные операторы|Постфиксные операторы]] &lt;br /&gt;
### [[Основные синтаксические конструкции#Тернарный условный оператор|Тернарный условный оператор]]&lt;br /&gt;
## [[Основные синтаксические конструкции#Оператор множественного выбора (switch)|Оператор множественного выбора (switch)]]&lt;br /&gt;
## [[Основные синтаксические конструкции#Циклы|Циклы]]&lt;br /&gt;
### [[Основные синтаксические конструкции#Цикл while|Цикл while]] &lt;br /&gt;
### [[Основные синтаксические конструкции#Цикл for|Цикл for]]&lt;br /&gt;
### [[Основные синтаксические конструкции#Цикл foreach|Цикл foreach]]&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;
## [[Управление пакетами#Импортирование библиотек, ключевое слово import|Импортирование библиотек, ключевое слово import]] &lt;br /&gt;
## [[Управление пакетами#Ключевое слово package|Ключевое слово package]]&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;
## [[Типы операторов#Аксессоры и мутаторы|Аксессоры и мутаторы]]&lt;br /&gt;
# [[Использование операторов]]&lt;br /&gt;
&lt;br /&gt;
== Системная библиотека ==&lt;br /&gt;
&lt;br /&gt;
== GIDE == &lt;br /&gt;
&lt;br /&gt;
# [[Идеология gide]]&lt;br /&gt;
# [[Виртуальная машина gide]]&lt;br /&gt;
# [[Стандартная библиотека gide]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Рабочие заметки]]&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/Release_Notes</id>
		<title>Release Notes</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/Release_Notes"/>
				<updated>2008-11-26T10:11:50Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;H2&amp;gt;''' Старьё! ''' &amp;lt;/H2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Данная страница отражает текущее состояние Deeptown SDK и его компонентов. Содержание этой страницы формируется из важных тонкостей, которые разработчики считают нужным донести до пользователей, а также из ответов на часто задаваемые вопросы по текущему релизу.&lt;br /&gt;
&lt;br /&gt;
Прежде чем написать [[Bugzilla|отчет об ошибке]], проверьте - нет ли этой ошибки в данном списке.&lt;br /&gt;
&lt;br /&gt;
== Ядро ==&lt;br /&gt;
&lt;br /&gt;
* остается неисправленной ошибка с корректным завершением работы. Проблема кроется в сетевом движке.&lt;br /&gt;
&lt;br /&gt;
== Компилятор [[K++]] ==&lt;br /&gt;
&lt;br /&gt;
* исходный код стандартной библиотеки K++: [http://dao.deeptown.org/misc/kpp.kpp kpp.kpp]&lt;br /&gt;
* не обрабатываются спецификаторы доступа. Т.е. все, что может быть экспортировано из класса или из модуля - экспортируется из него, а ключевые слова private, protected и public игнорируются.&lt;br /&gt;
* для объектов, работающих с консолью (STDIN, STDOUT, STDERR) в стандартной библиотеке не реализованы оберточные более удобные классы. Это связано с тем, что эти переменные устанавливаются только для текущего модуля, и из стандартной библиотеки недоступны. Ошибка будет исправлена путем изменения механизма передачи этих объектов пользовательскому коду.&lt;br /&gt;
* не доработан интерфейс класса string в плане удобства его использования.&lt;br /&gt;
&lt;br /&gt;
== Подсветка синтаксиса ==&lt;br /&gt;
&lt;br /&gt;
Пользователи KDE, для удобства работы с исходными текстами программ, могут установить написанные нами схемы подсветки синтаксиса для Katepart. После установки схем подсветки, все редакторы, которые используют этот виджет (Kate, KWrite, KDevelop, Krusader и др.), автоматически смогут правильно подсвечивать синтаксис исходных текстов, написанных на K++ и на Gide, а так же расставлять маркеры для свертки кода (code folding). &lt;br /&gt;
&lt;br /&gt;
Чтобы установить схемы подсветки, необходимо скачать их XML описания:&lt;br /&gt;
* [http://dao.deeptown.org/misc/kpp.xml Для K++]&lt;br /&gt;
* [http://dao.deeptown.org/misc/gide.xml Для Gide]&lt;br /&gt;
&lt;br /&gt;
А затем скопировать их в одну из нижеприведенных директорий:&lt;br /&gt;
 ~/.kde/share/apps/katepart/syntax/&lt;br /&gt;
 &amp;lt;путь к системным файлам kde&amp;gt;/&amp;lt;версия&amp;gt;/share/apps/katepart/syntax/&lt;br /&gt;
&lt;br /&gt;
Узнать место установки kde в вашей системе, как правило можно с помощью переменной среды KDEDIRS. Если схема будет установлена в системную директорию, то она будет доступна всем пользователям, а не только текущему.&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%9E_%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B5</id>
		<title>О проекте</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%9E_%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B5"/>
				<updated>2008-11-25T22:37:34Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* Участие */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Для кого эта wiki ==&lt;br /&gt;
&lt;br /&gt;
Наконец-то, после долгих лет разработки, проект [http://www.deeptown.org/ Deeptown] вплотную подобрался к этапу открытого тестирования. До этого момента разработка проекта велась в основном &amp;quot;вглубь&amp;quot; — мы проектировали основные технологии и писали реализацию их основ — т.е. скелет проекта. Теперь же, когда ядро платформы почти готово и, хоть и со скрипом, но работает, можно приступать к разработке приложений на его основе.&lt;br /&gt;
&lt;br /&gt;
Горизонты тут открываются достаточно широкие: начиная от драйверов хранения данных DISS и поддержки различных протоколов передачи, и заканчивая всевозможными приложениями на платформе Gide (пользовательский интерфейс, управление объектами, процедурные текстуры и многое другое).&lt;br /&gt;
&lt;br /&gt;
Очевидно, что нашей относительно небольшой команде разработчиков не справиться со всем этим в одиночку. К тому же, платформа для того и разрабатывалась, чтобы в дальнейшем разрабатывать на ее основе приложения; мы хотим предоставить эту возможность как можно раньше.&lt;br /&gt;
&lt;br /&gt;
Поэтому мы запустили ряд сервисов для тех, кто хотел бы участвовать в расширении платформы Диптауна, и в создании приложений на ее основе. Эта wiki является отправной точкой для доступа к этим сервисам. На ней также будет вестись разработка документации к различным технологиям и средствам разработки в рамках платформы Диптауна.&lt;br /&gt;
&lt;br /&gt;
Остальные сервисы включают в себя:&lt;br /&gt;
* [[Deeptown SDK|Deeptown Software Development Kit]] — набор программ и утилит для разработки системных и пользовательских приложений;&lt;br /&gt;
* [[Багтрекер]] — для отчетов об ошибках;&lt;br /&gt;
* [[Рассылка|Почтовая рассылка]] — включает в себя два списка рассылки: рассылку новостей и рассылку для обратной связи с разработчиками.&lt;br /&gt;
&lt;br /&gt;
== Участие ==&lt;br /&gt;
&lt;br /&gt;
Проект в целом и эта wiki в частности, подразумевают коллективную работу сообщества. Любой желающий может помочь проекту либо непосредственным участием в делах группы разработчиков, либо как вебмастер - установив на своем сайте ссылку на наш проект, либо косвенно, как посетитель этого сайта. Как вы уже могли заметить, на сайте и на wiki представлено большое количество материалов. Однако мы не в силах всецело контролировать качество публикуемых текстов, хотя и стремимся к этому.&lt;br /&gt;
&lt;br /&gt;
Вы можете помочь проекту даже не будучи программистом или дизайнером. Для этого достаточно просто быть грамотным человеком. Если на страницах этой wiki вы встретите неточности, орфографические или пунктуационные ошибки, или просто заметите дефиc там, где должно стоять тире — исправьте, пожалуйста, текст так, как вы считаете нужным. Это можно сделать с помощью вкладки &amp;quot;правка&amp;quot; вверху каждой страницы.&lt;br /&gt;
&lt;br /&gt;
Если вы сомневаетесь относительно верности вашего исправления, напишите об этом на странице обсуждения. Не забудьте только указать место в тексте, где, по вашему мнению, находится ошибка, и ваш вариант её исправления. Ссылка на страницу обсуждения также находится вверху каждой страницы.&lt;br /&gt;
&lt;br /&gt;
== Некоторые понятия  == &lt;br /&gt;
Наше название: '''Проект «Диптаун»'''&amp;lt;br&amp;gt;&lt;br /&gt;
По-английски: '''«Deeptown project»''' &amp;lt;br&amp;gt;&lt;br /&gt;
Слово «Deeptown» принято переводить как '''«Город-в-Глубине»''' &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Наш официальный сайт:&amp;lt;br&amp;gt; [http://www.deeptown.org www.deeptown.org]&amp;lt;br&amp;gt;&lt;br /&gt;
Наш официальный баннер:&amp;lt;br&amp;gt; [[Изображение:Deep_1_88x31.gif|Официальный баннер для сайта 'deeptown.org']]&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/Class</id>
		<title>Class</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/Class"/>
				<updated>2008-11-25T22:31:45Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* getStaticMethod */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Основной задачей класса &amp;lt;tt&amp;gt;Class&amp;lt;/tt&amp;gt; является предоставление механизма рефлексии. Сущность его заключается в том, что программист может получить инетресующую его информацию о классах и объектах прямо по ходу выполнения программы. В то время как класс &amp;lt;tt&amp;gt;[[Object]]&amp;lt;/tt&amp;gt; ставит своей задачей управление собственно объектами, то есть инстанциями классов, класс &amp;lt;tt&amp;gt;Class&amp;lt;/tt&amp;gt; используется для управления самими классами от которых были порождены соответствующие объекты. Ирония заключается в том что инстанции класса &amp;lt;tt&amp;gt;Class&amp;lt;/tt&amp;gt;, будучи потомками класса &amp;lt;tt&amp;gt;[[Object]]&amp;lt;/tt&amp;gt;, сами представляют классы. &lt;br /&gt;
&lt;br /&gt;
'''Родители''': &amp;lt;tt&amp;gt;[[Object]]&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
'''Методы''': &amp;lt;tt&amp;gt;[[#name|name]] [[#parents|parents]] [[#childOf|childOf]] [[#managed|managed]] [[#inspect|inspect]] [[#hasStaticMethod|hasStaticMethod]] [[#getStaticMethod|getStaticMethod]]&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
'''Реализует операторы''': &lt;br /&gt;
&amp;lt;tt&amp;gt;[[#оператор ==|==]]&amp;lt;/tt&amp;gt;,&lt;br /&gt;
&amp;lt;tt&amp;gt;[[#оператор &amp;lt;&amp;gt;|&amp;lt;&amp;gt;]]&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
&lt;br /&gt;
== оператор == ==&lt;br /&gt;
&lt;br /&gt;
operator == (''объект сравнения'') &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': [[логическое значение]] &amp;lt;br&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 x = (5.class == 6.class);   //значение: истина&lt;br /&gt;
var x = ('5'.class == 6.class); //значение: ложь&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== оператор &amp;lt;&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
operator &amp;lt;&amp;gt; (''объект сравнения'') &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': [[логическое значение]] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Инверсия оператора &amp;quot;&amp;lt;tt&amp;gt;[[#оператор ==|==]]&amp;lt;/tt&amp;gt;&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' В языке К++ используется форма &amp;quot;&amp;lt;tt&amp;gt;!=&amp;lt;/tt&amp;gt;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== name ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': &amp;lt;tt&amp;gt;[[string]]&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод возвращает имя класса. Эквивалент &amp;lt;tt&amp;gt;[[Object#className|Object:className]]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== parents ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': &amp;lt;tt&amp;gt;[[array]]&amp;lt;[[string]]&amp;gt;&amp;lt;/tt&amp;gt; &amp;lt;br&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 my = new MyClass;&lt;br /&gt;
const parents = my.class.parents;&lt;br /&gt;
for (var i = 0 ; i &amp;lt; parents.size; i++)&lt;br /&gt;
    //обработка полученных данных&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;
var my = new MyClass;&lt;br /&gt;
my.class.parents.each() { |parent| /* обработка полученных данных */; };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== childOf ==&lt;br /&gt;
&lt;br /&gt;
childOf(''имя класса:'' &amp;lt;tt&amp;gt;[[string]]&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': [[логическое значение]] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяет, унаследован ли текущий класс от указанного класса.&lt;br /&gt;
&lt;br /&gt;
== managed ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': [[логическое значение]] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяет, является ли текущий класс [[управляемые и неуправляемые классы|управляемым]] или нет.&lt;br /&gt;
&lt;br /&gt;
== inspect ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': &amp;lt;tt&amp;gt;[[string]]&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Возвращает информацию о классе. См. также &amp;lt;tt&amp;gt;[[Object#inspect|Object:inspect]]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== hasStaticMethod ==&lt;br /&gt;
&lt;br /&gt;
hasStaticMethod(''имя статического метода:'' &amp;lt;tt&amp;gt;[[string]]&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': [[логическое значение]] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяет, имеет ли класс указанный статический метод.&lt;br /&gt;
&lt;br /&gt;
== getStaticMethod ==&lt;br /&gt;
&lt;br /&gt;
getStaticMethod(''имя статического метода:'' &amp;lt;tt&amp;gt;[[string]]&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': &amp;lt;tt&amp;gt;[[Method]]&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данный метод возвращает статический метод класса в виде объекта. Впоследствии, этот объект может использоваться для удаленного вызова метода, либо для получения дополнительной информации. При попытке получения несуществующего метода будет возбуждено исключение &amp;lt;tt&amp;gt;[[Классы исключений#ENotFound|ENotFound]]&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;
var rnd = System.getClass('std/int').getStaticMethod('random');&lt;br /&gt;
var x = rnd();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В вышеприведенном примере, с помощью класса &amp;lt;tt&amp;gt;[[System]]&amp;lt;/tt&amp;gt;, мы получаем класс &amp;lt;tt&amp;gt;[[int]]&amp;lt;/tt&amp;gt; и создаем объект, соответствующий статическому методу &amp;lt;tt&amp;gt;random&amp;lt;/tt&amp;gt;. Объект метода сохраняется в переменной ''rnd''. Обращаясь к этой переменной как к функции, мы неявным образом вызываем сам метод.&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/Class</id>
		<title>Class</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/Class"/>
				<updated>2008-11-25T22:30:51Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* getStaticMethod */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Основной задачей класса &amp;lt;tt&amp;gt;Class&amp;lt;/tt&amp;gt; является предоставление механизма рефлексии. Сущность его заключается в том, что программист может получить инетресующую его информацию о классах и объектах прямо по ходу выполнения программы. В то время как класс &amp;lt;tt&amp;gt;[[Object]]&amp;lt;/tt&amp;gt; ставит своей задачей управление собственно объектами, то есть инстанциями классов, класс &amp;lt;tt&amp;gt;Class&amp;lt;/tt&amp;gt; используется для управления самими классами от которых были порождены соответствующие объекты. Ирония заключается в том что инстанции класса &amp;lt;tt&amp;gt;Class&amp;lt;/tt&amp;gt;, будучи потомками класса &amp;lt;tt&amp;gt;[[Object]]&amp;lt;/tt&amp;gt;, сами представляют классы. &lt;br /&gt;
&lt;br /&gt;
'''Родители''': &amp;lt;tt&amp;gt;[[Object]]&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
'''Методы''': &amp;lt;tt&amp;gt;[[#name|name]] [[#parents|parents]] [[#childOf|childOf]] [[#managed|managed]] [[#inspect|inspect]] [[#hasStaticMethod|hasStaticMethod]] [[#getStaticMethod|getStaticMethod]]&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
'''Реализует операторы''': &lt;br /&gt;
&amp;lt;tt&amp;gt;[[#оператор ==|==]]&amp;lt;/tt&amp;gt;,&lt;br /&gt;
&amp;lt;tt&amp;gt;[[#оператор &amp;lt;&amp;gt;|&amp;lt;&amp;gt;]]&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
&lt;br /&gt;
== оператор == ==&lt;br /&gt;
&lt;br /&gt;
operator == (''объект сравнения'') &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': [[логическое значение]] &amp;lt;br&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 x = (5.class == 6.class);   //значение: истина&lt;br /&gt;
var x = ('5'.class == 6.class); //значение: ложь&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== оператор &amp;lt;&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
operator &amp;lt;&amp;gt; (''объект сравнения'') &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': [[логическое значение]] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Инверсия оператора &amp;quot;&amp;lt;tt&amp;gt;[[#оператор ==|==]]&amp;lt;/tt&amp;gt;&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' В языке К++ используется форма &amp;quot;&amp;lt;tt&amp;gt;!=&amp;lt;/tt&amp;gt;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== name ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': &amp;lt;tt&amp;gt;[[string]]&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод возвращает имя класса. Эквивалент &amp;lt;tt&amp;gt;[[Object#className|Object:className]]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== parents ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': &amp;lt;tt&amp;gt;[[array]]&amp;lt;[[string]]&amp;gt;&amp;lt;/tt&amp;gt; &amp;lt;br&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 my = new MyClass;&lt;br /&gt;
const parents = my.class.parents;&lt;br /&gt;
for (var i = 0 ; i &amp;lt; parents.size; i++)&lt;br /&gt;
    //обработка полученных данных&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;
var my = new MyClass;&lt;br /&gt;
my.class.parents.each() { |parent| /* обработка полученных данных */; };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== childOf ==&lt;br /&gt;
&lt;br /&gt;
childOf(''имя класса:'' &amp;lt;tt&amp;gt;[[string]]&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': [[логическое значение]] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяет, унаследован ли текущий класс от указанного класса.&lt;br /&gt;
&lt;br /&gt;
== managed ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': [[логическое значение]] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяет, является ли текущий класс [[управляемые и неуправляемые классы|управляемым]] или нет.&lt;br /&gt;
&lt;br /&gt;
== inspect ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': &amp;lt;tt&amp;gt;[[string]]&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Возвращает информацию о классе. См. также &amp;lt;tt&amp;gt;[[Object#inspect|Object:inspect]]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== hasStaticMethod ==&lt;br /&gt;
&lt;br /&gt;
hasStaticMethod(''имя статического метода:'' &amp;lt;tt&amp;gt;[[string]]&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': [[логическое значение]] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяет, имеет ли класс указанный статический метод.&lt;br /&gt;
&lt;br /&gt;
== getStaticMethod ==&lt;br /&gt;
&lt;br /&gt;
getStaticMethod(''имя статического метода:'' &amp;lt;tt&amp;gt;[[string]]&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': &amp;lt;tt&amp;gt;[[Method]]&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данный метод возвращает статический метод класса в виде объекта. Впоследствии, этот объект может использоваться для удаленного вызова метода, либо для получения дополнительной информации. При попытке получения несуществующего метода будет возбуждено исключение &amp;lt;tt&amp;gt;[[Классы исключений#ENotFound|ENotFound]]&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;
var rnd = System.getClass('std/int').getStaticMethod('random');&lt;br /&gt;
var x = rnd();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В вышеприведенном примере, с помощью класса &amp;lt;tt&amp;gt;[[System]]&amp;lt;/tt&amp;gt;, мы получаем класс &amp;lt;tt&amp;gt;[[int]]&amp;lt;/tt&amp;gt; и создаем объект, соответствующий статическому методу &amp;lt;tt&amp;gt;random&amp;lt;/tt&amp;gt;. Объект метода сохраняется в переменной ''c''. Обращаясь к этой переменной как к функции, мы неявным образом вызываем сам метод.&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/Class</id>
		<title>Class</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/Class"/>
				<updated>2008-11-25T22:29:08Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* parents */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Основной задачей класса &amp;lt;tt&amp;gt;Class&amp;lt;/tt&amp;gt; является предоставление механизма рефлексии. Сущность его заключается в том, что программист может получить инетресующую его информацию о классах и объектах прямо по ходу выполнения программы. В то время как класс &amp;lt;tt&amp;gt;[[Object]]&amp;lt;/tt&amp;gt; ставит своей задачей управление собственно объектами, то есть инстанциями классов, класс &amp;lt;tt&amp;gt;Class&amp;lt;/tt&amp;gt; используется для управления самими классами от которых были порождены соответствующие объекты. Ирония заключается в том что инстанции класса &amp;lt;tt&amp;gt;Class&amp;lt;/tt&amp;gt;, будучи потомками класса &amp;lt;tt&amp;gt;[[Object]]&amp;lt;/tt&amp;gt;, сами представляют классы. &lt;br /&gt;
&lt;br /&gt;
'''Родители''': &amp;lt;tt&amp;gt;[[Object]]&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
'''Методы''': &amp;lt;tt&amp;gt;[[#name|name]] [[#parents|parents]] [[#childOf|childOf]] [[#managed|managed]] [[#inspect|inspect]] [[#hasStaticMethod|hasStaticMethod]] [[#getStaticMethod|getStaticMethod]]&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
'''Реализует операторы''': &lt;br /&gt;
&amp;lt;tt&amp;gt;[[#оператор ==|==]]&amp;lt;/tt&amp;gt;,&lt;br /&gt;
&amp;lt;tt&amp;gt;[[#оператор &amp;lt;&amp;gt;|&amp;lt;&amp;gt;]]&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
&lt;br /&gt;
== оператор == ==&lt;br /&gt;
&lt;br /&gt;
operator == (''объект сравнения'') &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': [[логическое значение]] &amp;lt;br&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 x = (5.class == 6.class);   //значение: истина&lt;br /&gt;
var x = ('5'.class == 6.class); //значение: ложь&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== оператор &amp;lt;&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
operator &amp;lt;&amp;gt; (''объект сравнения'') &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': [[логическое значение]] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Инверсия оператора &amp;quot;&amp;lt;tt&amp;gt;[[#оператор ==|==]]&amp;lt;/tt&amp;gt;&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' В языке К++ используется форма &amp;quot;&amp;lt;tt&amp;gt;!=&amp;lt;/tt&amp;gt;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== name ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': &amp;lt;tt&amp;gt;[[string]]&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод возвращает имя класса. Эквивалент &amp;lt;tt&amp;gt;[[Object#className|Object:className]]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== parents ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': &amp;lt;tt&amp;gt;[[array]]&amp;lt;[[string]]&amp;gt;&amp;lt;/tt&amp;gt; &amp;lt;br&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 my = new MyClass;&lt;br /&gt;
const parents = my.class.parents;&lt;br /&gt;
for (var i = 0 ; i &amp;lt; parents.size; i++)&lt;br /&gt;
    //обработка полученных данных&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;
var my = new MyClass;&lt;br /&gt;
my.class.parents.each() { |parent| /* обработка полученных данных */; };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== childOf ==&lt;br /&gt;
&lt;br /&gt;
childOf(''имя класса:'' &amp;lt;tt&amp;gt;[[string]]&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': [[логическое значение]] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяет, унаследован ли текущий класс от указанного класса.&lt;br /&gt;
&lt;br /&gt;
== managed ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': [[логическое значение]] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяет, является ли текущий класс [[управляемые и неуправляемые классы|управляемым]] или нет.&lt;br /&gt;
&lt;br /&gt;
== inspect ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': &amp;lt;tt&amp;gt;[[string]]&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Возвращает информацию о классе. См. также &amp;lt;tt&amp;gt;[[Object#inspect|Object:inspect]]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== hasStaticMethod ==&lt;br /&gt;
&lt;br /&gt;
hasStaticMethod(''имя статического метода:'' &amp;lt;tt&amp;gt;[[string]]&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': [[логическое значение]] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяет, имеет ли класс указанный статический метод.&lt;br /&gt;
&lt;br /&gt;
== getStaticMethod ==&lt;br /&gt;
&lt;br /&gt;
getStaticMethod(''имя статического метода:'' &amp;lt;tt&amp;gt;[[string]]&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': &amp;lt;tt&amp;gt;[[Method]]&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данный метод возвращает статический метод класса в виде объекта. Впоследствии, этот объект может использоваться для удаленного вызова метода, либо для получения дополнительной информации. При попытке получения несуществующего метода будет возбуждено исключение &amp;lt;tt&amp;gt;[[Классы исключений#ENotFound|ENotFound]]&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;
var c = System.getClass('std/int').getStaticMethod('random');&lt;br /&gt;
var rnd = c();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В вышеприведенном примере, с помощью класса &amp;lt;tt&amp;gt;[[System]]&amp;lt;/tt&amp;gt;, мы получаем класс &amp;lt;tt&amp;gt;[[int]]&amp;lt;/tt&amp;gt; и создаем объект, соответствующий статическому методу &amp;lt;tt&amp;gt;random&amp;lt;/tt&amp;gt;. Объект метода сохраняется в переменной ''c''. Обращаясь к этой переменной как к функции, мы неявным образом вызываем сам метод.&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/Object</id>
		<title>Object</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/Object"/>
				<updated>2008-11-25T22:20:41Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* inspect */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Класс &amp;lt;tt&amp;gt;Object&amp;lt;/tt&amp;gt; является сердцем всей стандартной библиотеки и ее центральным классом. Все остальные классы, прямо или косвенно наследуются от &amp;lt;tt&amp;gt;Object&amp;lt;/tt&amp;gt;, что позволяет реализовывать централизованное управление и сбор информации об объектах. Данный класс имеет набор методов которые реализуют механизм рефлексии, который заключается в том, что объекты могут динамически получать информацию о других объектах (включая самих себя). Например, объект A может узнать, какие методы имеет объект B, и на основании этой информации выполнять те или иные действия. &lt;br /&gt;
&lt;br /&gt;
Класс &amp;lt;tt&amp;gt;Object&amp;lt;/tt&amp;gt; вводит понятие инспектирования объектов, которое позволяет получать сведения о содержимом объектов в удобной для восприятия форме (это может быть особенно полезно при отладке и трассировке программ).&lt;br /&gt;
&lt;br /&gt;
'''Родители''': &amp;lt;tt&amp;gt;Object&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
'''Методы''': &amp;lt;tt&amp;gt;[[#class|class]] [[#className|className]] [[#instanceOf|instanceOf]] [[#call|call]] [[#invoke|invoke]] [[#freeze|freeze]] [[#frozen|frozen]] [[#clone|clone]] [[#dup|dup]] [[#inspect|inspect]] [[#equals|equals]] [[#hasMethod|hasMethod]] [[#getMethod|getMethod]] [[#methods|methods]]&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
'''Реализует операторы''': &amp;lt;tt&amp;gt;[[#equals|==]]&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
&lt;br /&gt;
== class ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': &amp;lt;tt&amp;gt;[[Class]]&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод возвращает инстанцию класса &amp;lt;tt&amp;gt;[[Class]]&amp;lt;/tt&amp;gt;, соответствующую классу данного объекта. Например:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var x = 1;        //переменная типа int&lt;br /&gt;
var c = x.class;  //переменная типа Class&lt;br /&gt;
puts(c.name);     //выведет на экран строку &amp;quot;int&amp;quot;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== className ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': &amp;lt;tt&amp;gt;[[string]]&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Эквивалент операции &amp;lt;tt&amp;gt;x.class.name&amp;lt;/tt&amp;gt;, только работает быстрее (без создания промежуточного объекта)&lt;br /&gt;
&lt;br /&gt;
== instanceOf ==&lt;br /&gt;
&lt;br /&gt;
instanceOf(''имя класса:'' &amp;lt;tt&amp;gt;[[string]]&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
instanceOf(''класс:'' &amp;lt;tt&amp;gt;[[Class]]&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': [[логическое значение]] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяет, является ли текущий объект инстанцией указанного класса.&lt;br /&gt;
&lt;br /&gt;
== call ==&lt;br /&gt;
&lt;br /&gt;
call(''имя метода:'' &amp;lt;tt&amp;gt;[[string]]&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;'''...'''&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': динамическую переменную &amp;lt;br&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 ary = new array; &lt;br /&gt;
ary.call(:push, 1, 2, 3);&lt;br /&gt;
puts(ary.inspect); // [1, 2, 3]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== invoke ==&lt;br /&gt;
&lt;br /&gt;
invoke(''имя метода:'' &amp;lt;tt&amp;gt;[[string]]&amp;lt;/tt&amp;gt;, ''параметры:'' &amp;lt;tt&amp;gt;[[array]]&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': динамическую переменную &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод аналогичен по смыслу методу &amp;lt;tt&amp;gt;[[#call|call]]&amp;lt;/tt&amp;gt;, за исключением того, что последующие параметры передаются в массиве. При вызове этот массив будет &amp;quot;развернут&amp;quot;, как если бы все параметры были записаны через запятую:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var ary = new array; &lt;br /&gt;
ary.invoke(:push, [1, 2, 3]);&lt;br /&gt;
puts(ary.inspect); // [1, 2, 3]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== freeze ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': текущий объект &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод &amp;quot;замораживает&amp;quot; текущий объект, после чего он становится доступным только для чтения. Обратной операции не существует, так что разморозить однажды замороженный объект нельзя.&lt;br /&gt;
&lt;br /&gt;
== frozen ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': [[логическое значение]] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяет, является ли текущий объект замороженным.&lt;br /&gt;
&lt;br /&gt;
== clone ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': копию текущего объекта &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод служит для создания копии текущего объекта, используя оператор &amp;quot;&amp;lt;tt&amp;gt;=&amp;lt;/tt&amp;gt;&amp;quot;. Если объект (или его класс) располагает таким методом, будет создана пустая инстанция класса, которой будет присвоено значение текущего объекта.&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' В случае с контейнерами копирование происходит только в том случае, если данный элемент обладает оператором &amp;quot;&amp;lt;tt&amp;gt;=&amp;lt;/tt&amp;gt;&amp;quot;; в противном случае, в копии контейнера будет лежать тот же объект:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var ary = new array; &lt;br /&gt;
ary.push(5);&lt;br /&gt;
ary.push(Stream.open(...));&lt;br /&gt;
var copy = ary.clone;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В этом примере, переменная ''copy'' будет содержать копию оригинального массива ''ary''. Однако скопирован будет только нулевой элемент массива, то есть объект соответствующий константе 5. Инстанция потока будет передана &amp;quot;как есть&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== dup ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== inspect ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': &amp;lt;tt&amp;gt;[[string]]&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод преобразует и возвращает информацию об объекте в удобном для восприятия виде. Переопределяется в классах-потомках для отображения более детальной информации. Во многих случаях является аналогом оператора приведения к строке, однако не всегда. Например, в случае K++, для класса строки оператор приведения к типу &amp;lt;tt&amp;gt;[[string]]&amp;lt;/tt&amp;gt; возвращает саму строку, тогда как метод &amp;lt;tt&amp;gt;inspect&amp;lt;/tt&amp;gt; возвращает строку с восстановленными спецсимволами и заключенную в кавычки:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var hello = &amp;quot;hello\tworld\n&amp;quot;;&lt;br /&gt;
puts(hello);           //вывод: hello    world&lt;br /&gt;
puts(hello as string); //вывод: hello    world&lt;br /&gt;
puts(hello.inspect);   //вывод: &amp;quot;hello\tworld\n&amp;quot;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Другие классы, такие как контейнеры переопределяют метод для отображения своего содержимого. При этом, в коде метода рекурсивно вызывается метод &amp;lt;tt&amp;gt;inspect&amp;lt;/tt&amp;gt; самих элементов для отображения их значения:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
var ary = [1, [2,'3'], :x, { :a =&amp;gt; 1 }];&lt;br /&gt;
puts(ary.inspect);  //вывод: [1, [2, &amp;quot;3&amp;quot;], &amp;quot;x&amp;quot;, { &amp;quot;a&amp;quot; =&amp;gt; 1 }]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== equals ==&lt;br /&gt;
&lt;br /&gt;
equals(''объект сравнения'') &amp;lt;br&amp;gt;&lt;br /&gt;
operator == (''объект сравнения'') &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': [[логическое значение]] &amp;lt;br&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 x = 5;&lt;br /&gt;
var b1 = x.equals(x);&lt;br /&gt;
var y = 4 + 1;&lt;br /&gt;
var b2 = x.equals(y);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В этом примере переменная ''b1'' будет истинной, в то время как переменная ''b2'' ложной. Несмотря на то, что переменные ''x'' и ''y'' равны численно — они представлены разными объектами.&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' В случае с классом &amp;lt;tt&amp;gt;Object&amp;lt;/tt&amp;gt; для тех же целей может применяться и оператор &amp;lt;tt&amp;gt;==&amp;lt;/tt&amp;gt;, однако предполагается что он должен переопределяться дочерними классами для достижения собственных целей. Сам же метод &amp;lt;tt&amp;gt;equals&amp;lt;/tt&amp;gt; переопределяться не должен никогда (для обеспечения оригинального функционала).&lt;br /&gt;
&lt;br /&gt;
== hasMethod ==&lt;br /&gt;
&lt;br /&gt;
hasMethod(''имя метода:'' &amp;lt;tt&amp;gt;[[string]]&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': [[логическое значение]] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяет, имеет ли объект указанный метод.&lt;br /&gt;
&lt;br /&gt;
== getMethod ==&lt;br /&gt;
&lt;br /&gt;
getMethod(''имя метода:'' &amp;lt;tt&amp;gt;[[string]]&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': &amp;lt;tt&amp;gt;[[Method]]&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данный метод возвращает метод объекта в виде объекта метода =) Впоследствии, этот объект может использоваться для удаленного вызова метода, либо для получения дополнительной информации. При попытке получения несуществующего метода будет возбуждено исключение &amp;lt;tt&amp;gt;[[Классы исключений#ENotFound|ENotFound]]&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;
var ary = new array;&lt;br /&gt;
var p = ary.getMethod(:push);&lt;br /&gt;
p(1, 2, 3);&lt;br /&gt;
ary.inspect; //значение: [1, 2, 3]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== methods ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': &amp;lt;tt&amp;gt;[[array]]&amp;lt;[[string]]&amp;gt;&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод возвращает массив имен методов.&lt;br /&gt;
&lt;br /&gt;
'''Примечание:''' Результирующий массив создается по требованию при каждом вызове метода. Поэтому, при необходимости перебора элементов, следует сначала сохранить полученный массив в переменную, а затем работать уже с ней.&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/Array</id>
		<title>Array</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/Array"/>
				<updated>2008-11-25T22:16:56Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* индексные операторы */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Класс &amp;lt;tt&amp;gt;array&amp;lt;/tt&amp;gt; предназначен для хранения данных в виде цельного блока, что позволяет производить быстрый поиск требуемого элемента на основании его индекса (смещения относительно начала блока). Данный контейнер предполагается использовать в тех случаях, когда требуется высокая скорость доступа к элементам, но операции добавления/удаления элементов просиходят сравнительно редко.&lt;br /&gt;
&lt;br /&gt;
'''Родители''': &amp;lt;tt&amp;gt;[[Object]]&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
'''Методы''': &amp;lt;tt&amp;gt;&lt;br /&gt;
[[#индексные операторы|at]]&lt;br /&gt;
[[#индексные операторы|set]]&lt;br /&gt;
[[#empty|empty]] &lt;br /&gt;
[[#size|size]] &lt;br /&gt;
[[#size=|size=]] &lt;br /&gt;
[[#size=|resize]] &lt;br /&gt;
[[#clear|clear]] &lt;br /&gt;
[[#push|push]] &lt;br /&gt;
[[#pop|pop]] &lt;br /&gt;
[[#top|top]]&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
'''Реализует операторы''': &lt;br /&gt;
[[#индексные операторы|индексного доступа]],&lt;br /&gt;
[[оператор присваивания|присваивания]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
&lt;br /&gt;
== индексные операторы  ==&lt;br /&gt;
&lt;br /&gt;
operator &amp;lt;nowiki&amp;gt;[]&amp;lt;/nowiki&amp;gt; (''индекс'': &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
at(''индекс'': &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': &amp;lt;tt&amp;gt;[[Object]]&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Оператор индексного чтения служит для получения объекта расположенного по указанному индексу. Если указан индекс, выходящий за текущие границы массива, будет сгенерировано исключение &amp;lt;tt&amp;gt;[[Классы исключений#ERangeError|ERangeError]]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
operator &amp;lt;nowiki&amp;gt;[]=&amp;lt;/nowiki&amp;gt; (''индекс'': &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;, ''значение'') &amp;lt;br&amp;gt;&lt;br /&gt;
set(''индекс'': &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;, ''значение'') &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': текущий объект &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Оператор индексной записи, напротив, служит для записи объекта по соответствующему индексу. Если указан индекс, выходящий за текущие границы массива, будет сгенерировано исключение &amp;lt;tt&amp;gt;[[Классы исключений#ERangeError|ERangeError]]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Примечание''': см. [[копирование в контейнерах]].&lt;br /&gt;
&lt;br /&gt;
== empty ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': [[логическое значение]] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод возвращает истину, если массив непуст. &lt;br /&gt;
&lt;br /&gt;
== size ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': &amp;lt;tt&amp;gt;[[int]]&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод возвращает текущее количество элементов массива. &lt;br /&gt;
&lt;br /&gt;
== size= ==&lt;br /&gt;
&lt;br /&gt;
size= (''новый размер'': &amp;lt;tt&amp;gt;[[int]]&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
resize(''новый размер'': &amp;lt;tt&amp;gt;[[int]]&amp;lt;/tt&amp;gt;) &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': текущий объект &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод устанавливает новый размер массива, сохраняя существующие данные на своих местах. При этом, новые ячейки будут содержать значение &amp;lt;tt&amp;gt;'''null'''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== clear ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': текущий объект &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Очищает массив содержимого и сбрасывает внутренний буфер. После этого размер массива считается нулевым.&lt;br /&gt;
&lt;br /&gt;
== push ==&lt;br /&gt;
&lt;br /&gt;
push(''объект'') &amp;lt;br&amp;gt;&lt;br /&gt;
'''Возвращает''': текущий объект &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод добавляет переданный объект в конец массива, расширяя массив при необходимости.&lt;br /&gt;
&lt;br /&gt;
'''Примечание''': см. [[копирование в контейнерах]].&lt;br /&gt;
&lt;br /&gt;
== pop ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': &amp;lt;tt&amp;gt;[[Object]]&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод возвращает объект с максимальным индексом и извлекает его из массива. Если сделана попытка извлечь объект из пустого массива, то будет сгенерировано исключение &amp;lt;tt&amp;gt;[[Классы исключений#ERangeError|ERangeError]]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== top ==&lt;br /&gt;
&lt;br /&gt;
'''Возвращает''': &amp;lt;tt&amp;gt;[[Object]]&amp;lt;/tt&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод возвращает объект с максимальным индексом, оставляя его в массиве. Если сделана попытка извлечь объект из пустого массива, то будет сгенерировано исключение &amp;lt;tt&amp;gt;[[Классы исключений#ERangeError|ERangeError]]&amp;lt;/tt&amp;gt;.&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%9C%D0%B5%D1%85%D0%B0%D0%BD%D0%B8%D0%B7%D0%BC%D1%8B_%D0%B2%D0%B7%D0%B0%D0%B8%D0%BC%D0%BE%D0%B4%D0%B5%D0%B9%D1%81%D1%82%D0%B2%D0%B8%D1%8F_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%BE%D0%B2_%D1%81_%D0%BE%D0%BA%D1%80%D1%83%D0%B6%D0%B0%D1%8E%D1%89%D0%B5%D0%B9_%D1%81%D1%80%D0%B5%D0%B4%D0%BE%D0%B9</id>
		<title>Механизмы взаимодействия объектов с окружающей средой</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%9C%D0%B5%D1%85%D0%B0%D0%BD%D0%B8%D0%B7%D0%BC%D1%8B_%D0%B2%D0%B7%D0%B0%D0%B8%D0%BC%D0%BE%D0%B4%D0%B5%D0%B9%D1%81%D1%82%D0%B2%D0%B8%D1%8F_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%BE%D0%B2_%D1%81_%D0%BE%D0%BA%D1%80%D1%83%D0%B6%D0%B0%D1%8E%D1%89%D0%B5%D0%B9_%D1%81%D1%80%D0%B5%D0%B4%D0%BE%D0%B9"/>
				<updated>2008-11-02T05:31:19Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* Взаимодействие объекта с окружающей средой */&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;
Рассмотрим эти взаимодействия подробнее.&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;
Например, когда аватар пользователя нажимает на кнопку, объект-аватар передает объекту-кнопке событие со смыслом &amp;quot;я тебя нажал&amp;quot;. Объект-кнопка получает уведомление о приходе события, и может выполнить в этот момент какие-либо действия.&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;
На данный момент реализовано лишь одно такое действие — init, уведомляющее объект о том, что он только что был создан.&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; на 1, а клиентский скрипт на это реагирует включением соответствующего источника света в графическом движке; таким образом создается иллюзия того, что лампа &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;
Список моторов объекта строго задан в его файле данных и не может быть динамически изменен. Фактически, моторы определяют возможное поведение объекта в пространстве. Например, у объекта &amp;quot;ракета&amp;quot; есть мотор — &amp;quot;двигатель&amp;quot;, который позволяет ракете взмывать над землей. Объект может управлять своими моторами, включая и выключая их, а также устанавливая некоторые параметры, зависящие от конкретных типов моторов.&lt;br /&gt;
&lt;br /&gt;
Мотор задается в файле описания объекта тегом &amp;lt;motor&amp;gt; в корневой секции, например:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;model bxd=&amp;quot;http://dao.deeptown.org/bxd/model.bxd&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- ... --&amp;gt;&lt;br /&gt;
    &amp;lt;motor name=&amp;quot;engine&amp;quot; url=&amp;quot;linear_speed:cube:(0,1,0)&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/model&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Как мы видим, мотор задается именем, по которому к нему потом можно будет обращаться, и URL адресом, в котором указывается тип мотора и его параметры. В приведенном выше примере, тип мотора — &amp;lt;tt&amp;gt;linear_speed&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>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%9C%D0%B5%D1%85%D0%B0%D0%BD%D0%B8%D0%B7%D0%BC%D1%8B_%D0%B2%D0%B7%D0%B0%D0%B8%D0%BC%D0%BE%D0%B4%D0%B5%D0%B9%D1%81%D1%82%D0%B2%D0%B8%D1%8F_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%BE%D0%B2_%D1%81_%D0%BE%D0%BA%D1%80%D1%83%D0%B6%D0%B0%D1%8E%D1%89%D0%B5%D0%B9_%D1%81%D1%80%D0%B5%D0%B4%D0%BE%D0%B9</id>
		<title>Механизмы взаимодействия объектов с окружающей средой</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%9C%D0%B5%D1%85%D0%B0%D0%BD%D0%B8%D0%B7%D0%BC%D1%8B_%D0%B2%D0%B7%D0%B0%D0%B8%D0%BC%D0%BE%D0%B4%D0%B5%D0%B9%D1%81%D1%82%D0%B2%D0%B8%D1%8F_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%BE%D0%B2_%D1%81_%D0%BE%D0%BA%D1%80%D1%83%D0%B6%D0%B0%D1%8E%D1%89%D0%B5%D0%B9_%D1%81%D1%80%D0%B5%D0%B4%D0%BE%D0%B9"/>
				<updated>2008-11-02T05:25:38Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* Взаимодействие объектов друг с другом. События */&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;
Рассмотрим эти взаимодействия подробнее.&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;
Например, когда аватар пользователя нажимает на кнопку, объект-аватар передает объекту-кнопке событие со смыслом &amp;quot;я тебя нажал&amp;quot;. Объект-кнопка получает уведомление о приходе события, и может выполнить в этот момент какие-либо действия.&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;
На данный момент реализовано лишь одно такое действие — init, уведомляющее объект о том, что он только что был создан.&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; на 1, а клиентский скрипт на это реагирует включением соответствующего источника света в графическом движке; таким образом создается иллюзия того, что лампа &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;
Список моторов объекта строго задан в его файле данных и не может быть динамически изменен. Фактически, моторы определяют возможное поведение объекта в пространстве. Например, у объекта &amp;quot;ракета&amp;quot; есть мотор — &amp;quot;двигатель&amp;quot;, который позволяет ракете взмывать над землей. Объект может управлять своими моторами, включая и выключая их, а также устанавливая некоторые параметры, зависящие от конкретных типов моторов.&lt;br /&gt;
&lt;br /&gt;
Мотор задается в файле описания объекта тегом &amp;lt;motor&amp;gt; в корневой секции, например:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;model bxd=&amp;quot;http://dao.deeptown.org/bxd/model.bxd&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- ... --&amp;gt;&lt;br /&gt;
    &amp;lt;motor name=&amp;quot;engine&amp;quot; url=&amp;quot;linear_speed:cube:(0,1,0)&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/model&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Как мы видим, мотор задается именем, по которому к нему потом можно будет обращаться, и URL адресом, в котором указывается тип мотора и его параметры. В приведенном выше примере, тип мотора — &amp;lt;tt&amp;gt;linear_speed&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>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%9F%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BF%D0%BE%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D1%8F_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%B0</id>
		<title>Программирование поведения объекта</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%9F%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BF%D0%BE%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D1%8F_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%B0"/>
				<updated>2008-11-01T15:49:46Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* Создание простого объекта */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Перейдем от теории к практике. Перед прочтением этого документа рекомендуется ознакомиться с предыдущими. Здесь приведены конкретные рецепты - как и что делать, с примерами и их разбором.&lt;br /&gt;
&lt;br /&gt;
== Где хранить файлы? ==&lt;br /&gt;
&lt;br /&gt;
Ядро Диптауна использует DISS для хранения файлов. По-умолчанию, в корень DISS монтируется директория, которая находится в подкаталоге storage архива media. Таким образом,&lt;br /&gt;
* в linux это директория, которая расположена в $DEEPTOWN_MEDIA/storage&lt;br /&gt;
* в windows - INSTALL_DIR/Media/storage&lt;br /&gt;
&lt;br /&gt;
DISS при первом запуске индексирует рекурсивно все файлы своего каталога (это необходимо для выполнения сложных запросов к файловой системе). Поэтому, если Вы добавляете или удаляете какие-либо файлы где-либо в пределах этой директории, нужно удалить файл '''_index''' в ее корне, чтобы при следующем запуске DISS переиндексировал каталог заново, и &amp;quot;увидел&amp;quot; бы внесенные изменения.&lt;br /&gt;
&lt;br /&gt;
Далее в документе, везде, где указан путь к файлу, имеется ввиду DISS-путь.&lt;br /&gt;
&lt;br /&gt;
Для хранения объектов, в корне DISS есть подкаталог media, в котором есть следующие подкаталоги:&lt;br /&gt;
* materials - для хранения файлов материалов;&lt;br /&gt;
* meshes - для графических 3d моделей;&lt;br /&gt;
* models - для файлов объектов;&lt;br /&gt;
* scenes - для файлов сцен;&lt;br /&gt;
* scripts - для файлов скриптов;&lt;br /&gt;
* textures - для текстур.&lt;br /&gt;
&lt;br /&gt;
Отметим, что это лишь рекомендованные пути; Вы можете использовать любые другие в пределах DISS.&lt;br /&gt;
&lt;br /&gt;
== Создание простого объекта ==&lt;br /&gt;
&lt;br /&gt;
Для того, чтобы создать объект, нужны&lt;br /&gt;
* файл материала;&lt;br /&gt;
* файл 3d модели в формате OGRE mesh;&lt;br /&gt;
* необходимые материалу текстуры.&lt;br /&gt;
&lt;br /&gt;
Все это можно получить, воспользовавшись одним из конверторов, доступных на [http://www.ogre3d.org/index.php?option=com_content&amp;amp;task=view&amp;amp;id=413&amp;amp;Itemid=133 официальном сайте OGRE].&lt;br /&gt;
&lt;br /&gt;
Пожалуйста, обратите внимание, что все размеры в файле 3d модели должны указываться '''в метрах'''.&lt;br /&gt;
&lt;br /&gt;
Если конвертер создает несколько файлов материалов, нужно объединить их в один (в произвольном порядке). Кроме того, нужно '''переправить пути к текстурам''' в файлах материалов на абсолютные DISS-пути (т.е. '''/media/textures/...''').&lt;br /&gt;
&lt;br /&gt;
Когда все это сделано, остается последний шаг - создать файл модели. Для этого нужно создать XML-файл объекта, который, в простейшем случае, выглядит следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;model bxd=&amp;quot;http://dao.deeptown.org/bxd/model.bxd&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;material_script node=&amp;quot;путь к файлу материала&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;body name=&amp;quot;main_body&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;geometry&amp;gt;&lt;br /&gt;
            &amp;lt;!-- описание геометрии объекта --&amp;gt;&lt;br /&gt;
        &amp;lt;/geometry&amp;gt;&lt;br /&gt;
        &amp;lt;surfaces&amp;gt;&lt;br /&gt;
            &amp;lt;mesh name=&amp;quot;cube&amp;quot; node=&amp;quot;путь к файлу 3d модели&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/surfaces&amp;gt;&lt;br /&gt;
    &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/model&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Чтобы теперь сконвертировать этот файл в bxl, воспользуйтесь командой&lt;br /&gt;
 bxd filename.model.xml -f filename.model&lt;br /&gt;
&lt;br /&gt;
где filename.model.xml - имя исходного файла, filename.model - имя получаемого файла модели.&lt;br /&gt;
&lt;br /&gt;
Для того, чтобы использовать объект локально, необходимо задать его UID, записав его в метаинформацию DISS. В той же директории, где находится этот файл, создайте файл '''.meta''' и напишите туда следующее:&lt;br /&gt;
 [filename.model]&lt;br /&gt;
 version = 0.1&lt;br /&gt;
 wso_node = 1&lt;br /&gt;
 wso_uid = 0101-0001-00000001-0000000000000001&lt;br /&gt;
&lt;br /&gt;
UID (последняя строчка) должен различаться для каждой копии объекта в пространстве. Если один и тот же объект нужно использовать в сцене несколько раз, можно задать ему несколько UID-ов в метаинформации - задав несколько записей wso_uid.&lt;br /&gt;
&lt;br /&gt;
В самом UID-е можно менять только последний (самый длинный) блок цифр (это шестнадцатиричные цифры, т.е. от 0 до F).&lt;br /&gt;
&lt;br /&gt;
Если в директории находится несколько объектов, дописывайте в .meta секции одну за другой. Файл .meta сканируется при создании индекса DISS, так что при внесении изменений нужно удалять '''.index'''.&lt;br /&gt;
&lt;br /&gt;
=== Создание динамического объекта ===&lt;br /&gt;
&lt;br /&gt;
Объект, приведенный в примере выше, будет статичным, т.е. все время находиться в одном и том же месте пространства (обладать бесконечной массой). Если нужен динамический объект, следует добавить в описание модели информацию о массе и моменте инерции объекта:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;body name=&amp;quot;main_body&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;mass_data&amp;gt;&lt;br /&gt;
        &amp;lt;mass value=&amp;quot;1&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;inertia i11=&amp;quot;1&amp;quot; i22=&amp;quot;1&amp;quot; i33=&amp;quot;1&amp;quot; i12=&amp;quot;0&amp;quot; i13=&amp;quot;0&amp;quot; i23=&amp;quot;0&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/mass_data&amp;gt;&lt;br /&gt;
    &amp;lt;!-- ... --&amp;gt;&lt;br /&gt;
&amp;lt;/body&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;
 | i11  i12  i13 |&lt;br /&gt;
 | i12  i22  i23 |&lt;br /&gt;
 | i13  i23  i33 |&lt;br /&gt;
&lt;br /&gt;
Вы можете не указывать тег '''inertia''' для простых тестов, но в этом случае объект будет вести себя неестественно.&lt;br /&gt;
&lt;br /&gt;
== Связывание объекта со скриптом ==&lt;br /&gt;
&lt;br /&gt;
Для того, чтобы получить возможность программировать поведение объекта, нужно прописать в него адрес скрипта. Добавьте внутрь корневого XML-тега следующее:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;externals&amp;gt;&lt;br /&gt;
    &amp;lt;event_receiver url=&amp;quot;gide:/media/scripts/my_object.gbc!MyObject&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/externals&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В этом случае объект будет передавать все свои события объекту гайд-класса MyObject, объявленного в файле /media/scripts/my_object.gbc.&lt;br /&gt;
&lt;br /&gt;
В этом файле должен находиться '''скомпилированный''' код класса. Простейший, ничего не делающий код такого класса на [[K++]] выглядит следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;kpp&amp;quot;&amp;gt;&lt;br /&gt;
package my_object;&lt;br /&gt;
&lt;br /&gt;
import world;&lt;br /&gt;
&lt;br /&gt;
class MyObject extends WorldObject&lt;br /&gt;
{&lt;br /&gt;
    export function State_init()&lt;br /&gt;
    {&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Напишите этот код в файл my_object.kpp в той же директории. Компилируется он командой&lt;br /&gt;
 kpp my_object.kpp&lt;br /&gt;
&lt;br /&gt;
== Добавление мотора ==&lt;br /&gt;
&lt;br /&gt;
Мотор - это интерфейс объекта, позволяющий контролировать его поведение.&lt;br /&gt;
&lt;br /&gt;
Все моторы объекта должны быть описаны в его файле модели. Делается это добавлением тега '''motor''' в корневую секцию:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;motor name=&amp;quot;engine&amp;quot; url=&amp;quot;linear_speed:main_body:(0,1,0)&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Такой тег создаст мотор '''engine''' с типом '''linear_speed''', прикладывающий силу к телу '''main_body''' (параметр '''name''' в теге '''body''') по вектору направления (0,1,0) - т.е. вверх.&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;
export function State_init()&lt;br /&gt;
{&lt;br /&gt;
    var engine = this.getMotor('engine'); // получили интерфейс мотора&lt;br /&gt;
                            // первый параметр - имя, указанное при создании мотора (см. выше)&lt;br /&gt;
    engine.setParam('speed', 100); // максимальная скорость, сообщаемая объекту&lt;br /&gt;
    engine.setParam('force', 100); // максимальная сила, которая будет приложена для разгона&lt;br /&gt;
    engine.enable();  // включаем мотор&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;
Например, нам нужно, чтобы мотор был включен только пока нажата клавиша A на клавиатуре.&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;
В файл '''/etc/world/input.conf''' в контекст '''local_control''' нужно добавить следующие строки:&lt;br /&gt;
 on key_press   check(key=A) do send_event:start_engine&lt;br /&gt;
 on key_release check(key=A) do send_event:stop_engine&lt;br /&gt;
&lt;br /&gt;
Таким образом, когда пользователь нажимает клавишу A, нашему объекту будет отправлено уведомление '''start_engine''', а когда отпускает - '''stop_engine'''.&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;
export function Control_start_engine(const bytea args)&lt;br /&gt;
{&lt;br /&gt;
    this.getMotor('engine').enable();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
export function Control_stop_engine(const bytea args)&lt;br /&gt;
{&lt;br /&gt;
    this.getMotor('engine').disable();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(предполагается, что параметры мотора были установлены при инициализации, т.е. в State_init).&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;
export function State_init()&lt;br /&gt;
{&lt;br /&gt;
    // создаем сенсор высоты&lt;br /&gt;
    this.createSensor('height:&amp;gt;100', 'too_high');&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
export function Signal_too_high(const bytea args)&lt;br /&gt;
{&lt;br /&gt;
    // метод будет вызван при срабатывании сенсора, т.е. когда абсолютная&lt;br /&gt;
    // высота объекта превысит 100 метров.&lt;br /&gt;
    this.getMotor('engine').disable();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Имя функции-обработчика формируется из префикса '''Signal_''' и второго параметра функции '''createSensor'''.&lt;br /&gt;
&lt;br /&gt;
== Создание сцены ==&lt;br /&gt;
&lt;br /&gt;
Для того, чтобы теперь посмотреть на созданные объекты, нужно создать сцену и разместить на ней эти объекты, и затем загрузить сцену в движок.&lt;br /&gt;
&lt;br /&gt;
Сцена также описывается в формате BXL. XML-файл сцены выглядит довольно просто:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;scene bxd=&amp;quot;http://dao.deeptown.org/bxd/scene.bxd&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;model uid=&amp;quot;0101-0001-00000001-0000000000000002&amp;quot;&lt;br /&gt;
        x=&amp;quot;0.2&amp;quot; y=&amp;quot;0&amp;quot; z=&amp;quot;-5&amp;quot;&lt;br /&gt;
        qw=&amp;quot;1&amp;quot; qx=&amp;quot;0&amp;quot; qy=&amp;quot;0&amp;quot; qz=&amp;quot;0&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/scene&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тегов '''model''' может быть сколь угодно много. В параметрах этого тега указываются координаты объекта на сцене и кватернион его поворота.&lt;br /&gt;
&lt;br /&gt;
== Пуск! ==&lt;br /&gt;
&lt;br /&gt;
И теперь остался последний момент - загрузить все это в движок.&lt;br /&gt;
&lt;br /&gt;
Для этого нужно набрать консольную команду&lt;br /&gt;
 world.local_start /media/scenes/filename.scene UID&lt;br /&gt;
&lt;br /&gt;
Первый параметр - имя файла сцены, второй - UID объекта, которому будет передаваться ввод пользователя.&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%9F%D0%BE%D0%BD%D1%8F%D1%82%D0%B8%D0%B5_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%B0_%D0%B2_%D0%BF%D1%80%D0%BE%D1%81%D1%82%D1%80%D0%B0%D0%BD%D1%81%D1%82%D0%B2%D0%B5</id>
		<title>Понятие объекта в пространстве</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%9F%D0%BE%D0%BD%D1%8F%D1%82%D0%B8%D0%B5_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%B0_%D0%B2_%D0%BF%D1%80%D0%BE%D1%81%D1%82%D1%80%D0%B0%D0%BD%D1%81%D1%82%D0%B2%D0%B5"/>
				<updated>2008-11-01T15:30:36Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* Представления объекта */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Введение ==&lt;br /&gt;
&lt;br /&gt;
Ключевым понятием в World Engine является Объект. Под этим понятием подразумевается некоторая атомарная сущность, которая может взаимодействовать с:&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;
* [http://www.gamedev.ru/users/wat/articles/quaternions кватернионом] вращения.&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; объектом.&lt;br /&gt;
# ''Фаербол'', эмиттеры частиц (дым, огонь и т. д) либо другие графические фокусы. Представляются в графическом пространстве.&lt;br /&gt;
# ''Поля сил'' как проявления заклинаний или обычного ветра. Представляются в физическом пространстве.&lt;br /&gt;
&lt;br /&gt;
== Данные объекта ==&lt;br /&gt;
&lt;br /&gt;
Данные объекта хранятся в [[DISS]] файле в формате [[BXL]]. Объект также может зависеть от других файлов (скрипты, текстуры и др.), ссылки на которые приводятся в основном файле.&lt;br /&gt;
&lt;br /&gt;
Полный набор свойств объекта, которые можно задать в его файле, достаточно обширен, поэтому сейчас я не буду приводить его полностью — когда этот формат будет окончательно утвержден, будет и документация по нему. В этом разделе я приведу несколько примеров простых объектов с описанием, а в последующих разделах буду приводить информацию о других тегах, если это потребуется.&lt;br /&gt;
&lt;br /&gt;
Все примеры приведены в формате XML; для конвертирования из XML в BXL существует утилита bxd — на данный момент она реализована на Perl. Для конвертирования объекта, наберите команду&lt;br /&gt;
 bxd filename.model.xml -f filename.model&lt;br /&gt;
где filename.model.xml — имя файла с XML описанием.&lt;br /&gt;
&lt;br /&gt;
=== Простейший физический объект ===&lt;br /&gt;
&lt;br /&gt;
Рассмотрим пример файла, описывающего куб размером 1x1x1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;model bxd=&amp;quot;http://dao.deeptown.org/bxd/model.bxd&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;material_script node=&amp;quot;/media/materials/cube.material&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;body name=&amp;quot;cube&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;geometry&amp;gt;&lt;br /&gt;
            &amp;lt;geom type=&amp;quot;box&amp;quot; width=&amp;quot;1&amp;quot; height=&amp;quot;1&amp;quot; depth=&amp;quot;1&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/geometry&amp;gt;&lt;br /&gt;
        &amp;lt;surfaces&amp;gt;&lt;br /&gt;
            &amp;lt;mesh name=&amp;quot;cube&amp;quot; node=&amp;quot;/media/meshes/cube_small.mesh&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/surfaces&amp;gt;&lt;br /&gt;
    &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/model&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;1-11:Все описание объекта заключено в тег '''model''', у которого нет параметров (кроме стандартной ссылки на BXD-описание для корректного конвертирования в BXL);&lt;br /&gt;
;2:Тег '''material_script''' указывает на путь к файлу описания материалов. Формат этого файла описан в [http://www.ogre3d.org/docs/manual/manual_14.html документации OGRE]. Важно отметить, что внутри этого файла, все ссылки на текстуры, шейдеры и пр. делаются также указанием DISS-пути к соответствующему файлу;&lt;br /&gt;
;3:Тег '''body''' описывает '''твердое тело''', которое становится частью нашего объекта. В рамках одного объекта таких тел может быть несколько — каждое из них будет описываться отдельным тегом body;&lt;br /&gt;
;4:В рамках тега '''geometry''' содержится информация о геометрических примитивах, связанных с данным твердым телом, т.е. о его физическом представлении;&lt;br /&gt;
;5:Куб в пространстве легко описывается примитивом '''box''' — паралеллепипедом с указанными шириной, высотой и глубиной (оси x, y и z соответственно). Обратите внимание, что по-умолчанию примитив находится в центре локальных координат данного твердого тела. Сместить его можно тегом '''position''', следующим образом:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;geom type=&amp;quot;box&amp;quot; width=&amp;quot;1&amp;quot; height=&amp;quot;1&amp;quot; depth=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;position x=&amp;quot;1&amp;quot; y=&amp;quot;0&amp;quot; z=&amp;quot;0&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/geom&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
:Такая конструкция сместила бы примитив на 1 (метр) по оси X относительно локальных координат твердого тела. Аналогично, тегом '''rotation''' с параметрами qw, qx, qy и qz можно задать кватернион вращения данного примитива относительно локальной системы координат.&lt;br /&gt;
;7-9:В рамках тега '''surfaces''' задаются графические примитивы, связанные с объектом. В нашем случае такой примитив только один: тег '''node''' указывает имя файла с графическим описанием куба в формате OGRE Mesh (конвертеры в этот формат можно скачать с [http://www.ogre3d.org официального сайта OGRE], там также имеется [http://www.ogre3d.org/wiki/index.php/OGRE_DCC_Tools набор инструментов] для создания графического контента).&lt;br /&gt;
&lt;br /&gt;
Еще раз обращаю Ваше внимание на то, что физическая и графическая модели объекта хоть и связаны, но разделены. Например, если бы мы в теге geometry указали бы в качестве примитива не куб, а шар, — данный объект все равно выглядел бы кубом (потому что графическое представление мы бы не поменяли), но вел бы себя с точки зрения физики как шар (мог бы покатиться по земле, например).&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;xml&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;model bxd=&amp;quot;http://dao.deeptown.org/bxd/model.bxd&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;material_script node=&amp;quot;/media/materials/cube.material&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;body name=&amp;quot;cube&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;mass_data&amp;gt;&lt;br /&gt;
            &amp;lt;mass value=&amp;quot;1&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/mass_data&amp;gt;&lt;br /&gt;
        &amp;lt;geometry&amp;gt;&lt;br /&gt;
            &amp;lt;geom type=&amp;quot;box&amp;quot; width=&amp;quot;1&amp;quot; height=&amp;quot;1&amp;quot; depth=&amp;quot;1&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/geometry&amp;gt;&lt;br /&gt;
        &amp;lt;surfaces&amp;gt;&lt;br /&gt;
            &amp;lt;mesh name=&amp;quot;cube&amp;quot; node=&amp;quot;/media/meshes/cube_small.mesh&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/surfaces&amp;gt;&lt;br /&gt;
    &amp;lt;/body&amp;gt;&lt;br /&gt;
    &amp;lt;externals&amp;gt;&lt;br /&gt;
        &amp;lt;event_receiver url=&amp;quot;gide:/media/scripts/cube_small_dynamic.gbc!CubeSmallDynamic&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/externals&amp;gt;&lt;br /&gt;
&amp;lt;/model&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Рассмотрим теги, которые были добавлены в этот файл:&lt;br /&gt;
;4-6:Тег '''mass_data''' определяет механическое представление тела. В нем можно задать массу (тег '''mass''') и матрицу инерции (не указанный здесь тег '''inertia'''), которая по-умолчанию является единичной матрицой.&lt;br /&gt;
;14-16:В теге '''externals''' приводятся дополнительные данные объекта. В данном случае, это тег '''event_receiver''', который определяет обработчик события.&lt;br /&gt;
&lt;br /&gt;
Обработчик события, как и многое другое, задается при помощи URL. Под URL всегда понимается некоторая строка, включающая в себя тип сущности (в данном случае — обработчика) и адрес этой сущности, который зависит от ее типа. Тип и адрес разделены двоеточием.&lt;br /&gt;
&lt;br /&gt;
Единственный на данный момент реализованный обработчик событий имеет тип gide. Этот обработчик передает все события некоторому объекту Gide-класса. В адресе указано имя файла скрипта (в DISS) и имя класса, разделенные символом &amp;quot;!&amp;quot;.&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%81%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8</id>
		<title>Алгоритм синхронизации</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%81%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8"/>
				<updated>2008-10-31T09:29:41Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* Поиск уравнения коррекции */&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;
:&amp;lt;math&amp;gt;s(t_i) = f(t_i), \quad s'(t_i) = f'(t_i)\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Уравнения сплайна:&lt;br /&gt;
:&amp;lt;math&amp;gt;s(t) = a + bt + ct^2 + dt^3\!&amp;lt;/math&amp;gt;&lt;br /&gt;
:&amp;lt;math&amp;gt;s'(t) = b + 2ct + 3dt^2\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Для нахождения коэффициентов &amp;lt;math&amp;gt;a, b, c, d&amp;lt;/math&amp;gt; записываем систему уравнений:&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
a + bt_0 + ct_0^2 + dt_0^3 = f(t_0) \\&lt;br /&gt;
a + bt_1 + ct_1^2 + dt_1^3 = f(t_1) \\&lt;br /&gt;
b + 2ct_0 + 3dt_0^2 = f'(t_0) \\&lt;br /&gt;
b + 2ct_1 + 3dt_1^2 = f'(t_1)&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Подставляем известные значения в правой части системы (даны по условию):&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
a + bt_0 + ct_0^2 + dt_0^3 = x_0 \\&lt;br /&gt;
a + bt_1 + ct_1^2 + dt_1^3 = x_1 \\&lt;br /&gt;
b + 2ct_0 + 3dt_0^2 = v_0 \\&lt;br /&gt;
b + 2ct_1 + 3dt_1^2 = v_1&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Поскольку сплайн не зависит от конкретных значений &amp;lt;math&amp;gt;t_0&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;t_1&amp;lt;/math&amp;gt;, положим &amp;lt;math&amp;gt;t_0 = 0&amp;lt;/math&amp;gt;, а &amp;lt;math&amp;gt;t_1 = t&amp;lt;/math&amp;gt;. В результате, пара уравнений становится тривиальной:&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
a = x_0 \\&lt;br /&gt;
a + bt + ct^2 + dt^3 = x_1 \\&lt;br /&gt;
b = v_0 \\&lt;br /&gt;
b + 2ct + 3dt^2 = v_1&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Заменяем в оставшихся уравнениях известные теперь коэффициенты и получаем конечную систему:&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
x_0 + v_0t + ct^2 + dt^3 = x_1 \\&lt;br /&gt;
v_0 + 2ct + 3dt^2 = v_1&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
После нехитрых манипуляций, получаем выражения для оставшихся коэффициентов:&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
c = \frac{3x_1 - 3x_0 - 2v_0t - v_1t}{t^2} \\&lt;br /&gt;
d = \frac{2x_0 - 2x_1 + v_0t + v_1t}{t^3}&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ниже представлены графики оригинальной функции с наложенным на них графиком сплайна, построенного по точкам. Парабола и экспонента построены по фиксированному набору точек (-2.5, -2, -0.5, 0.5, 2, 2.5). Синусоида построена по точкам с интервалом 0.05.&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
Изображение:Exp.gif|Экспонента&lt;br /&gt;
Изображение:Parabola2.gif|Парабола&lt;br /&gt;
Изображение:Sin.gif|Синус&lt;br /&gt;
&amp;lt;/gallery&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;
Коррекция осуществляется путем приложения сторонней силы к движущемуся телу так, чтобы &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;
Осталось убедиться, что сумма этих сил действительно стабилизирует траекторию движения объекта, не приведет к колебаниям, и найти оптимальные значения для коэффициентов двух сил.&lt;br /&gt;
&lt;br /&gt;
Чтобы упростить себе жизнь, рассмотрим двумерный случай. Пусть серверная траектория тела совпадает с осью X; клиентская траектория — параллельна этой оси и находится от нее на расстоянии, равном H. В нулевой момент времени тело находится в нуле по оси X как на клиентской, так и на серверной траекториях.&lt;br /&gt;
&lt;br /&gt;
Пусть и серверная, и клиентская точки имеют горизонтальную скорость &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt;, а по вертикальной оси они неподвижны. Никаких прочих сил на объект не действует. Поскольку никаких сил по горизонтали не действует, мы будем рассматривать только движение по оси y.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Сила коррекции высоты, по такой модели, будет направлена &amp;quot;вниз&amp;quot; на эту точку и будет равна: &lt;br /&gt;
:&amp;lt;math&amp;gt;F_p = - K_p \cdot y(t) \cdot V_x \cdot m&amp;lt;/math&amp;gt;&lt;br /&gt;
где &amp;lt;math&amp;gt;y&amp;lt;/math&amp;gt; — это высота точки и &lt;br /&gt;
:&amp;lt;math&amp;gt;y(0) = H\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Множитель &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; мы добавляем специально, чтобы уменьшить влияние силы коррекции на малых скоростях (иначе еле движущееся тело будет менять свое положение заметными глазу рывками).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Сила коррекции вертикальной скорости точки:&lt;br /&gt;
:&amp;lt;math&amp;gt;F_v = - K_v \cdot V_y(t) \cdot m&amp;lt;/math&amp;gt;&lt;br /&gt;
и &lt;br /&gt;
:&amp;lt;math&amp;gt;V_y(0) = 0\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Известно, что скорость — это производная координаты по времени:&lt;br /&gt;
:&amp;lt;math&amp;gt;V_y(t) = \frac{\partial y(t)}{\partial t}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Соответственно, сила, которая действует на объект:&lt;br /&gt;
:&amp;lt;math&amp;gt;F(t) = m \cdot y''(t) = F_p + F_v = - K_p \cdot y(t) \cdot V_x \cdot m - K_v \cdot V_y(t) \cdot m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;F - F_p - F_v = 0\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Разделив на массу, и записав уравнение в дифференциальной форме, получим:&lt;br /&gt;
:&amp;lt;math&amp;gt;y''(t) + K_v \cdot y'(t) + K_p \cdot y(t) \cdot Vx = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Перепишем параметрически:&lt;br /&gt;
:&amp;lt;math&amp;gt;y''(t) + A \cdot y'(t) + B \cdot y(t) = 0\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Характеристическое уравнение:&lt;br /&gt;
:&amp;lt;math&amp;gt;\lambda^2 + A \cdot \lambda + B = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Дискриминант характеристического уравнения:&lt;br /&gt;
:&amp;lt;math&amp;gt;D = A^2 - 4 \cdot B = K_v^2 - 4 \cdot K_p \cdot V_x&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для исключения колебательного процесса, необходимо условие &amp;lt;math&amp;gt;D \geqslant 0&amp;lt;/math&amp;gt;. Следовательно:&lt;br /&gt;
:&amp;lt;math&amp;gt;K_v^2 - 4 \cdot K_p \cdot V_x \geqslant 0&amp;lt;/math&amp;gt;&lt;br /&gt;
:&amp;lt;math&amp;gt;K_v^2 \geqslant 4 \cdot K_p \cdot V_x, \quad V_x \leqslant \frac{K_v^2}{4 \cdot K_p}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Видно, что если &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; будет больше чем эта дробь, то возникнут колебания (нарушается условие &amp;lt;math&amp;gt;D \geqslant 0&amp;lt;/math&amp;gt;). Поэтому, при малых скоростях используется само значение &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt;, а когда &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; численно становится больше этой дроби, следует заменять ее на эту дробь (ограничение сверху).&lt;br /&gt;
&lt;br /&gt;
В конечном счете, коэффициенты &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; выражаются как&lt;br /&gt;
:&amp;lt;math&amp;gt;\alpha_{1,2} = \frac{-K_v \pm \sqrt{D}}{2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Далее, найдем коэффициенты &amp;lt;math&amp;gt;C_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;C_2&amp;lt;/math&amp;gt;: &lt;br /&gt;
:&amp;lt;math&amp;gt;y(t) = C_1 \cdot e^{\alpha_1 t} + C_2 \cdot e^{\alpha_2 t}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Зная начальные условия  &amp;lt;math&amp;gt;y(0) = H&amp;lt;/math&amp;gt; (начальное расстояние между объектами) и &amp;lt;math&amp;gt;y'(t) = 0&amp;lt;/math&amp;gt; получаем уравнение:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_1 \cdot e^{\alpha_1 \cdot 0} + C_2 \cdot e^{\alpha_2 \cdot 0} = y(0) = H&amp;lt;/math&amp;gt; &lt;br /&gt;
следовательно &lt;br /&gt;
:&amp;lt;math&amp;gt;C_1 + C_2 = H\!&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из второго условия:&lt;br /&gt;
:&amp;lt;math&amp;gt;\alpha_1 \cdot C_1 \cdot e^{\alpha_1 \cdot 0} + \alpha_2 \cdot C_2 \cdot e^{\alpha_2 \cdot 0} = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
:&amp;lt;math&amp;gt;\alpha_1 \cdot C_1 + \alpha_2 \cdot C_2 = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Получаем систему следующих уравнений:&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
C_1 + C_2 = H \\&lt;br /&gt;
\alpha_1 \cdot C_1 + \alpha_2 \cdot C_2 = 0&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Решая систему относительно &amp;lt;math&amp;gt;C_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;C_2&amp;lt;/math&amp;gt;, получаем&lt;br /&gt;
:&amp;lt;math&amp;gt;C_{1,2} = \left ( \frac{1}{2} \pm \frac{K_v}{\sqrt{D}} \right ) \cdot H&amp;lt;/math&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;quot;между&amp;quot; коррекциями тело предоставлено само себе, оно и будет двигаться в указанную ему сторону. В худшем случае, при больших и плохо подобранных параметрах, уже после первого корректирующего воздействия, тело вылетит &amp;quot;за траекторию&amp;quot;, соответственно возникнут колебания (возможно даже возрастающие).&lt;br /&gt;
&lt;br /&gt;
Для избежания этого неприятного момента, попробуем оценить параметры и найти их &amp;quot;практический потолок&amp;quot;, с тем, чтобы не позволять пользователю задавать значения выходящие за границы.&lt;br /&gt;
&lt;br /&gt;
Итак, при моделировании, будем считать что в течение шага тело движется по прямой. Соответственно, сила, которая будет действовать на тело в течение первого шага, т.е. времени &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, будет равна &lt;br /&gt;
:&amp;lt;math&amp;gt;F_p = - K_p \cdot V_x \cdot H \cdot m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Соответственно, в течение первого шага тело будет двигаться с ускорением &lt;br /&gt;
:&amp;lt;math&amp;gt;a = - K_p \cdot Vx \cdot H&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Условие стабилизации — расстояние, которое преодолеет тело за первый шаг должно быть меньше &amp;lt;math&amp;gt;H&amp;lt;/math&amp;gt;:&lt;br /&gt;
:&amp;lt;math&amp;gt;K_p \cdot V_x \cdot H \cdot \frac{T^2}{2} &amp;lt; H, \quad K_p \cdot V_x \cdot T^2 &amp;lt; 2, \quad K_p &amp;lt; \frac{2}{V_x \cdot {T^2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Левая часть неравенства будет минимальной в случае, когда &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; максимальна, т.е. равна &amp;lt;math&amp;gt;\tfrac{K_v^2}{4 \cdot K_p}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Это означает, что в том случае когда модуль скорости тела меньше чем указанное значение, то коррекция будет происходить гладко; когда больше — в формуле для силы стабилизации положения &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; заменяется на &amp;lt;math&amp;gt;\tfrac{K_v^2}{4 \cdot K_p}&amp;lt;/math&amp;gt;. Объяснение было дано выше, при оценке дискриминанта характеристического уравнения.&lt;br /&gt;
&lt;br /&gt;
Из этого следует, что чтобы действительно сделать невидимым действие нашей силы на малых скоростях, необходимо, чтобы значение &amp;lt;math&amp;gt;\tfrac{K_v^2}{4 \cdot K_p}&amp;lt;/math&amp;gt; было бы достаточно большим. Мы взяли его по-умолчанию равным 10, но это значение можно бдет менять в свойствах каждого конкретного объекта.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Осталось только численно оценить коэффициенты &amp;lt;math&amp;gt;K_p&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;K_v&amp;lt;/math&amp;gt;. Для &amp;lt;math&amp;gt;K_p&amp;lt;/math&amp;gt; конкретное значение получается, если подставить в условие &lt;br /&gt;
:&amp;lt;math&amp;gt;K_p &amp;lt; \frac{2}{V_x \cdot T^2}&amp;lt;/math&amp;gt;&lt;br /&gt;
значения &amp;lt;math&amp;gt;V_x = 10&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;T = 0.04&amp;lt;/math&amp;gt;. Получается, что &amp;lt;math&amp;gt;K_p &amp;lt; 125&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Для нахождения &amp;lt;math&amp;gt;K_v&amp;lt;/math&amp;gt; вместо &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; необходимо подставить наибольшее возможное для нее значение &amp;lt;math&amp;gt;\tfrac{K_v^2}{4 \cdot K_p}&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;K_p &amp;lt; \frac{2}{\frac{K_v^2}{4 \cdot K_p} \cdot T^2}, \quad K_p &amp;lt; \frac{2 \cdot 4 \cdot K_p}{K_v^2 \cdot T^2}, \quad 1 &amp;lt; \frac{8}{K_v^2 \cdot T^2}, \quad K_v^2 &amp;lt; \frac{8}{T^2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Окончательно,&lt;br /&gt;
:&amp;lt;math&amp;gt;K_v &amp;lt; \frac{2\sqrt{2}}{T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
При подстановке значения &amp;lt;math&amp;gt;T = 0.04&amp;lt;/math&amp;gt;, получается, что &amp;lt;math&amp;gt;K_v &amp;lt; 70&amp;lt;/math&amp;gt;. В реальных условиях эти пределы взяты еще меньше, для защиты от граничных случаев. Конкретно, &amp;lt;math&amp;gt;K_p&amp;lt;/math&amp;gt; по-умолчанию не может превышать 50, а &amp;lt;math&amp;gt;K_v&amp;lt;/math&amp;gt; — 30&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
[20:40:39] &amp;lt;droot@deeptown.org&amp;gt; так&lt;br /&gt;
[20:40:44] &amp;lt;droot@deeptown.org&amp;gt; а теперь - самое веселое&lt;br /&gt;
[20:40:51] &amp;lt;droot@deeptown.org&amp;gt; все то же самое, но только для вращения =)&lt;br /&gt;
[20:46:32] &amp;lt;korvin&amp;gt; мде..&lt;br /&gt;
[20:46:56] &amp;lt;droot@deeptown.org&amp;gt; там почти то же самое&lt;br /&gt;
[20:47:00] &amp;lt;korvin&amp;gt; ну вообще там не должно быть сильно сложно&lt;br /&gt;
[20:47:02] &amp;lt;korvin&amp;gt; то же самое по сути&lt;br /&gt;
[20:47:09] &amp;lt;droot@deeptown.org&amp;gt; т.е. плоская задача там будет точно такой же&lt;br /&gt;
[20:47:24] &amp;lt;droot@deeptown.org&amp;gt; только не y(t), а fi(t) - угол от времени&lt;br /&gt;
[20:48:03] &amp;lt;droot@deeptown.org&amp;gt; я вот не могу сообразить, что будет являться трехмерным представлением этого угла&lt;br /&gt;
[20:48:37] &amp;lt;korvin&amp;gt; в смысле?&lt;br /&gt;
[20:49:14] &amp;lt;droot@deeptown.org&amp;gt; ну вот в случае движения, от нашей задачи можно легко перейти к трехмерной, просто взяв не y(t), а r(t) - вектор координаты&lt;br /&gt;
[20:49:18] &amp;lt;droot@deeptown.org&amp;gt; мм..&lt;br /&gt;
[20:49:23] &amp;lt;droot@deeptown.org&amp;gt; ну точнее не совсем так&lt;br /&gt;
[20:49:27] &amp;lt;droot@deeptown.org&amp;gt; там же надо разность брать&lt;br /&gt;
[20:49:32] &amp;lt;droot@deeptown.org&amp;gt; а, ну да&lt;br /&gt;
[20:49:44] &amp;lt;droot@deeptown.org&amp;gt; т.е. вместо y(t) мы пишем разность векторов между сервером и клиентом&lt;br /&gt;
[20:49:45] &amp;lt;korvin&amp;gt; ну там вроде же просто 3 угла, которые можно точно так же линейно интерполировать&lt;br /&gt;
[20:50:45] &amp;lt;droot@deeptown.org&amp;gt; Vx - это модуль серверной скорости&lt;br /&gt;
[20:50:58] &amp;lt;droot@deeptown.org&amp;gt; ну а все остальное понятно&lt;br /&gt;
[20:51:29] &amp;lt;droot@deeptown.org&amp;gt; что же касается углов&lt;br /&gt;
[20:51:41] &amp;lt;droot@deeptown.org&amp;gt; ну если посмотреть на задачу с практической точки зрения&lt;br /&gt;
[20:51:50] &amp;lt;droot@deeptown.org&amp;gt; т.е. у нас есть два кватерниона&lt;br /&gt;
[20:53:24] &amp;lt;droot@deeptown.org&amp;gt; надо сообразить, что будет являться кватернионом вращения из одного положения во второе&lt;br /&gt;
[20:53:50] &amp;lt;korvin&amp;gt; в смысле что будет?&lt;br /&gt;
[20:54:12] &amp;lt;korvin&amp;gt; м... может проще представить кватернион в виде косинусов и дальше по частям?&lt;br /&gt;
[20:54:21] &amp;lt;korvin&amp;gt; покомпонентно в смысле&lt;br /&gt;
[20:54:23] &amp;lt;droot@deeptown.org&amp;gt; это долго считать&lt;br /&gt;
[20:59:55] &amp;lt;droot@deeptown.org&amp;gt; мм ну вообще все понятно&lt;br /&gt;
[21:00:19] &amp;lt;droot@deeptown.org&amp;gt; если сумма вращений задается кватернионом Q = q2 * q1&lt;br /&gt;
[21:00:47] &amp;lt;droot@deeptown.org&amp;gt; то разность вращений будет q2 = Q * q1^(-1) = Q * q1'&lt;br /&gt;
[21:01:36] &amp;lt;droot@deeptown.org&amp;gt; т.е. мы легко можем посчитать кватернион, который является разностью между клиентским и серверным вращениями&lt;br /&gt;
[21:03:54] &amp;lt;droot@deeptown.org&amp;gt; для того, чтобы повернуть тело этим кватернионом, нам нужно приложить к нему момент вращения, направление которого также можно посчитать&lt;br /&gt;
[21:05:56] &amp;lt;droot@deeptown.org&amp;gt; а зависеть он будет от тех же модуля серверной угловой скорости, собсно кватерниона разности, момента вращения, ну и соответственно некоторого коэффициента&lt;br /&gt;
[21:08:54] &amp;lt;droot@deeptown.org&amp;gt; ну а для стабилизации разности угловых скоростей все элементарно: момент вращения будет просто пропорционален разности векторов угловых скоростей (ну и направлен вдоль вектора этой разности)&lt;br /&gt;
[21:11:22] &amp;lt;korvin&amp;gt; так, ну это понятно&lt;br /&gt;
[21:11:32] &amp;lt;korvin&amp;gt; а с перерегулированием что делать?&lt;br /&gt;
[21:11:37] &amp;lt;korvin&amp;gt; ну то есть если перестараемся&lt;br /&gt;
[21:11:41] &amp;lt;droot@deeptown.org&amp;gt; (я вот щас мысленно пытаюсь себе это представить и думаю нсчет вектора разности...)&lt;br /&gt;
[21:12:44] &amp;lt;droot@deeptown.org&amp;gt; там собсно соотношение этих коэффициентов точно такое же должно получиться&lt;br /&gt;
[21:13:34] &amp;lt;droot@deeptown.org&amp;gt; т.е. W &amp;lt; Kw^2 / (4*Kr)&lt;br /&gt;
[21:42:36] &amp;lt;droot@deeptown.org&amp;gt; хочешь почитать веселую книжку? =)&lt;br /&gt;
[21:43:09] &amp;lt;droot@deeptown.org&amp;gt; я тут с аленкой попробовал проконсультироваться, и она мне оч посоветовала =) ландау-лифшиц &amp;quot;механика&amp;quot; называется =)&lt;br /&gt;
[21:55:38] &amp;lt;droot@deeptown.org&amp;gt; вообще, вот что до ограничений сверху для этих всех коэффициентов - я думаю, что надо просто взять некую константу - скажем, 30 - и ей ограничиться&lt;br /&gt;
[21:55:53] &amp;lt;droot@deeptown.org&amp;gt; т.е. Kv &amp;lt; 30&lt;br /&gt;
[21:56:10] &amp;lt;droot@deeptown.org&amp;gt; ну, для Kp можно ограничение чуть больше - скажем, Kp &amp;lt; 50&lt;br /&gt;
[21:58:57] &amp;lt;droot@deeptown.org&amp;gt; мм. а вообще, я бы даже не так сделал&lt;br /&gt;
[21:59:22] &amp;lt;droot@deeptown.org&amp;gt; мне кажется что параметризовать надо не через Kp и Kv, а через Vx и Kp, а уже Kv выражать через них&lt;br /&gt;
[21:59:36] &amp;lt;korvin&amp;gt; мм&lt;br /&gt;
[21:59:39] &amp;lt;korvin&amp;gt; а смысл?&lt;br /&gt;
[21:59:41] &amp;lt;droot@deeptown.org&amp;gt; (ну т.е. Vx - это максимальная скорость)&lt;br /&gt;
[21:59:50] &amp;lt;droot@deeptown.org&amp;gt; а это более понятные пользователю числа&lt;br /&gt;
[22:01:30] &amp;lt;droot@deeptown.org&amp;gt; хотя... ладно, фиг с ним, пусть будет напрямую&lt;br /&gt;
[22:01:40] &amp;lt;droot@deeptown.org&amp;gt; надо еще подумать, какие значения по-умолчанию лучше всего взять&lt;br /&gt;
[22:01:59] &amp;lt;droot@deeptown.org&amp;gt; ну Vx видимо надо брать где-то 10 как раз - это 36 км/ч&lt;br /&gt;
[22:02:22] &amp;lt;korvin&amp;gt; 10 м/с не жирно ли?&lt;br /&gt;
[22:02:24] &amp;lt;droot@deeptown.org&amp;gt; при большей уже вряд ли будут заметны эти силы&lt;br /&gt;
[22:02:55] &amp;lt;droot@deeptown.org&amp;gt; ну 36 км/ч - это где-то как раз граница воспринимаемых скоростей имхо&lt;br /&gt;
[22:04:02] &amp;lt;droot@deeptown.org&amp;gt; Kv предлагаю взять равным где-то 20&lt;br /&gt;
[22:04:46] &amp;lt;droot@deeptown.org&amp;gt; при этом будет хороший запас до сваливания из-за шага рассчета, но и время стабилизации будет достаточно малым&lt;br /&gt;
[22:04:55] &amp;lt;droot@deeptown.org&amp;gt; ну а Kp щас посчитаем&lt;br /&gt;
[22:05:11] &amp;lt;droot@deeptown.org&amp;gt; Vx = Kv^2 / (4*Kp)&lt;br /&gt;
[22:05:26] &amp;lt;droot@deeptown.org&amp;gt; Kp = Vx * 4 / Kv^2&lt;br /&gt;
[22:05:37] &amp;lt;droot@deeptown.org&amp;gt; тьфу&lt;br /&gt;
[22:05:57] &amp;lt;droot@deeptown.org&amp;gt; Kp = Kv&amp;amp;2 / (Vx*4)&lt;br /&gt;
[22:06:31] &amp;lt;droot@deeptown.org&amp;gt; Kp = 20^2 / 40 = 10&lt;br /&gt;
[22:06:40] &amp;lt;droot@deeptown.org&amp;gt; ну, вполне себе круглые числа =)&lt;br /&gt;
[22:06:48] &amp;lt;droot@deeptown.org&amp;gt; Vx = 10, Kp = 10, Kv = 20&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%81%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8</id>
		<title>Алгоритм синхронизации</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%81%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8"/>
				<updated>2008-10-24T22:36:24Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* Построение сплайна */&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;
:&amp;lt;math&amp;gt;s(t_i) = f(t_i), \quad s'(t_i) = f'(t_i)\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Уравнения сплайна:&lt;br /&gt;
:&amp;lt;math&amp;gt;s(t) = a + bt + ct^2 + dt^3\!&amp;lt;/math&amp;gt;&lt;br /&gt;
:&amp;lt;math&amp;gt;s'(t) = b + 2ct + 3dt^2\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Для нахождения коэффициентов &amp;lt;math&amp;gt;a, b, c, d&amp;lt;/math&amp;gt; записываем систему уравнений:&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
a + bt_0 + ct_0^2 + dt_0^3 = f(t_0) \\&lt;br /&gt;
a + bt_1 + ct_1^2 + dt_1^3 = f(t_1) \\&lt;br /&gt;
b + 2ct_0 + 3dt_0^2 = f'(t_0) \\&lt;br /&gt;
b + 2ct_1 + 3dt_1^2 = f'(t_1)&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Подставляем известные значения в правой части системы (даны по условию):&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
a + bt_0 + ct_0^2 + dt_0^3 = x_0 \\&lt;br /&gt;
a + bt_1 + ct_1^2 + dt_1^3 = x_1 \\&lt;br /&gt;
b + 2ct_0 + 3dt_0^2 = v_0 \\&lt;br /&gt;
b + 2ct_1 + 3dt_1^2 = v_1&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Поскольку сплайн не зависит от конкретных значений &amp;lt;math&amp;gt;t_0&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;t_1&amp;lt;/math&amp;gt;, положим &amp;lt;math&amp;gt;t_0 = 0&amp;lt;/math&amp;gt;, а &amp;lt;math&amp;gt;t_1 = t&amp;lt;/math&amp;gt;. В результате, пара уравнений становится тривиальной:&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
a = x_0 \\&lt;br /&gt;
a + bt + ct^2 + dt^3 = x_1 \\&lt;br /&gt;
b = v_0 \\&lt;br /&gt;
b + 2ct + 3dt^2 = v_1&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Заменяем в оставшихся уравнениях известные теперь коэффициенты и получаем конечную систему:&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
x_0 + v_0t + ct^2 + dt^3 = x_1 \\&lt;br /&gt;
v_0 + 2ct + 3dt^2 = v_1&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
После нехитрых манипуляций, получаем выражения для оставшихся коэффициентов:&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
c = \frac{3x_1 - 3x_0 - 2v_0t - v_1t}{t^2} \\&lt;br /&gt;
d = \frac{2x_0 - 2x_1 + v_0t + v_1t}{t^3}&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ниже представлены графики оригинальной функции с наложенным на них графиком сплайна, построенного по точкам. Парабола и экспонента построены по фиксированному набору точек (-2.5, -2, -0.5, 0.5, 2, 2.5). Синусоида построена по точкам с интервалом 0.05.&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
Изображение:Exp.gif|Экспонента&lt;br /&gt;
Изображение:Parabola2.gif|Парабола&lt;br /&gt;
Изображение:Sin.gif|Синус&lt;br /&gt;
&amp;lt;/gallery&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;
Коррекция осуществляется путем приложения сторонней силы к движущемуся телу так, чтобы &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;
Осталось убедиться, что сумма этих сил действительно стабилизирует траекторию движения объекта, не приведет к колебаниям, и найти оптимальные значения для коэффициентов двух сил.&lt;br /&gt;
&lt;br /&gt;
Чтобы упростить себе жизнь, рассмотрим двумерный случай. Пусть серверная траектория тела совпадает с осью X; клиентская траектория — параллельна этой оси и находится от нее на расстоянии, равном H. В нулевой момент времени тело находится в нуле по оси X как на клиентской, так и на серверной траекториях.&lt;br /&gt;
&lt;br /&gt;
Пусть и серверная, и клиентская точки имеют горизонтальную скорость &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt;, а по вертикальной оси они неподвижны. Никаких прочих сил на объект не действует. Поскольку никаких сил по горизонтали не действует, мы будем рассматривать только движение по оси y.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Сила коррекции высоты, по такой модели, будет направлена &amp;quot;вниз&amp;quot; на эту точку и будет равна: &lt;br /&gt;
:&amp;lt;math&amp;gt;F_p = - K_p \cdot y(t) \cdot V_x \cdot m&amp;lt;/math&amp;gt;&lt;br /&gt;
где &amp;lt;math&amp;gt;y&amp;lt;/math&amp;gt; — это высота точки и &lt;br /&gt;
:&amp;lt;math&amp;gt;y(0) = H\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Множитель &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; мы добавляем специально, чтобы уменьшить влияние силы коррекции на малых скоростях (иначе еле движущееся тело будет менять свое положение заметными глазу рывками).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Сила коррекции вертикальной скорости точки:&lt;br /&gt;
:&amp;lt;math&amp;gt;F_v = - K_v \cdot V_y(t) \cdot m&amp;lt;/math&amp;gt;&lt;br /&gt;
и &lt;br /&gt;
:&amp;lt;math&amp;gt;V_y(0) = 0\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Известно, что скорость — это производная координаты по времени:&lt;br /&gt;
:&amp;lt;math&amp;gt;V_y(t) = \frac{\partial y(t)}{\partial t}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Соответственно, сила, которая действует на объект:&lt;br /&gt;
:&amp;lt;math&amp;gt;F(t) = m \cdot y''(t) = F_p + F_v = - K_p \cdot y(t) \cdot V_x \cdot m - K_v \cdot V_y(t) \cdot m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;F - F_p - F_v = 0\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Разделив на массу, и записав уравнение в дифференциальной форме, получим:&lt;br /&gt;
:&amp;lt;math&amp;gt;y''(t) + K_v \cdot y'(t) + K_p \cdot y(t) \cdot Vx = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Перепишем параметрически:&lt;br /&gt;
:&amp;lt;math&amp;gt;y''(t) + A \cdot y'(t) + B \cdot y(t) = 0\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Характеристическое уравнение:&lt;br /&gt;
:&amp;lt;math&amp;gt;\lambda^2 + A \cdot \lambda + B = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Дискриминант характеристического уравнения:&lt;br /&gt;
:&amp;lt;math&amp;gt;D = A^2 - 4 \cdot B = K_v^2 - 4 \cdot K_p \cdot V_x&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для исключения колебательного процесса, необходимо условие &amp;lt;math&amp;gt;D \geqslant 0&amp;lt;/math&amp;gt;. Следовательно:&lt;br /&gt;
:&amp;lt;math&amp;gt;K_v^2 - 4 \cdot K_p \cdot V_x \geqslant 0&amp;lt;/math&amp;gt;&lt;br /&gt;
:&amp;lt;math&amp;gt;K_v^2 \geqslant 4 \cdot K_p \cdot V_x, \quad V_x \leqslant \frac{K_v^2}{4 \cdot K_p}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Видно, что если &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; будет больше чем эта дробь, то возникнут колебания (нарушается условие &amp;lt;math&amp;gt;D \geqslant 0&amp;lt;/math&amp;gt;). Поэтому, при малых скоростях используется само значение &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt;, а когда &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; численно становится больше этой дроби, следует заменять ее на эту дробь (ограничение сверху).&lt;br /&gt;
&lt;br /&gt;
В конечном счете, коэффициенты &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; выражаются как&lt;br /&gt;
:&amp;lt;math&amp;gt;\alpha_{1,2} = \frac{-K_v \pm \sqrt{D}}{2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Далее, найдем коэффициенты &amp;lt;math&amp;gt;C_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;C_2&amp;lt;/math&amp;gt;: &lt;br /&gt;
:&amp;lt;math&amp;gt;y(t) = C_1 \cdot e^{\alpha_1 t} + C_2 \cdot e^{\alpha_2 t}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Зная начальные условия  &amp;lt;math&amp;gt;y(0) = H&amp;lt;/math&amp;gt; (начальное расстояние между объектами) и &amp;lt;math&amp;gt;y'(t) = 0&amp;lt;/math&amp;gt; получаем уравнение:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_1 \cdot e^{\alpha_1 \cdot 0} + C_2 \cdot e^{\alpha_2 \cdot 0} = y(0) = H&amp;lt;/math&amp;gt; &lt;br /&gt;
следовательно &lt;br /&gt;
:&amp;lt;math&amp;gt;C_1 + C_2 = H\!&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из второго условия:&lt;br /&gt;
:&amp;lt;math&amp;gt;\alpha_1 \cdot C_1 \cdot e^{\alpha_1 \cdot 0} + \alpha_2 \cdot C_2 \cdot e^{\alpha_2 \cdot 0} = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
:&amp;lt;math&amp;gt;\alpha_1 \cdot C_1 + \alpha_2 \cdot C_2 = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Получаем систему следующих уравнений:&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
C_1 + C_2 = H \\&lt;br /&gt;
\alpha_1 \cdot C_1 + \alpha_2 \cdot C_2 = 0&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Решая систему относительно &amp;lt;math&amp;gt;C_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;C_2&amp;lt;/math&amp;gt;, получаем&lt;br /&gt;
:&amp;lt;math&amp;gt;C_{1,2} = \left ( \frac{1}{2} \pm \frac{K_v}{\sqrt{D}} \right ) \cdot H&amp;lt;/math&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;quot;между&amp;quot; коррекциями тело предоставлено само себе, оно и будет двигаться в указанную ему сторону. В худшем случае, при больших и плохо подобранных параметрах, уже после первого корректирующего воздействия, тело вылетит &amp;quot;за траекторию&amp;quot;, соответственно возникнут колебания (возможно даже возрастающие).&lt;br /&gt;
&lt;br /&gt;
Для избежания этого неприятного момента, попробуем оценить параметры и найти их &amp;quot;практический потолок&amp;quot;, с тем, чтобы не позволять пользователю задавать значения выходящие за границы.&lt;br /&gt;
&lt;br /&gt;
Итак, при моделировании, будем считать что в течение шага тело движется по прямой. Соответственно, сила, которая будет действовать на тело в течение первого шага, т.е. времени &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, будет равна &lt;br /&gt;
:&amp;lt;math&amp;gt;F_p = - K_p \cdot V_x \cdot H \cdot m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Соответственно, в течение первого шага тело будет двигаться с ускорением &lt;br /&gt;
:&amp;lt;math&amp;gt;a = - K_p \cdot Vx \cdot H&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Условие стабилизации — расстояние, которое преодолеет тело за первый шаг должно быть меньше &amp;lt;math&amp;gt;H&amp;lt;/math&amp;gt;:&lt;br /&gt;
:&amp;lt;math&amp;gt;K_p \cdot V_x \cdot H \cdot \frac{T^2}{2} &amp;lt; H, \quad K_p \cdot V_x \cdot T^2 &amp;lt; 2, \quad K_p &amp;lt; \frac{2}{V_x \cdot {T^2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Левая часть неравенства будет минимальной в случае, когда &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; максимальна, т.е. равна &amp;lt;math&amp;gt;\tfrac{K_v^2}{4 \cdot K_p}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Это означает, что в том случае когда модуль скорости тела меньше чем указанное значение, то коррекция будет происходить гладко; когда больше — в формуле для силы стабилизации положения &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; заменяется на &amp;lt;math&amp;gt;\tfrac{K_v^2}{4 \cdot K_p}&amp;lt;/math&amp;gt;. Объяснение было дано выше, при оценке дискриминанта характеристического уравнения.&lt;br /&gt;
&lt;br /&gt;
Из этого следует, что чтобы действительно сделать невидимым действие нашей силы на малых скоростях, необходимо, чтобы значение &amp;lt;math&amp;gt;\tfrac{K_v^2}{4 \cdot K_p}&amp;lt;/math&amp;gt; было бы достаточно большим. Мы взяли его по-умолчанию равным 10, но это значение можно бдет менять в свойствах каждого конкретного объекта.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Осталось только численно оценить коэффициенты &amp;lt;math&amp;gt;K_p&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;K_v&amp;lt;/math&amp;gt;. Для &amp;lt;math&amp;gt;K_p&amp;lt;/math&amp;gt; конкретное значение получается, если подставить в условие &lt;br /&gt;
:&amp;lt;math&amp;gt;K_p &amp;lt; \frac{2}{V_x \cdot T^2}&amp;lt;/math&amp;gt;&lt;br /&gt;
значения &amp;lt;math&amp;gt;V_x = 10&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;T = 0.04&amp;lt;/math&amp;gt;. Получается, что &amp;lt;math&amp;gt;K_p &amp;lt; 125&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Для нахождения &amp;lt;math&amp;gt;K_v&amp;lt;/math&amp;gt; вместо &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; необходимо подставить наибольшее возможное для нее значение &amp;lt;math&amp;gt;\tfrac{K_v^2}{4 \cdot K_p}&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;K_p &amp;lt; \frac{2}{\frac{K_v^2}{4 \cdot K_p} \cdot T^2}, \quad K_p &amp;lt; \frac{2 \cdot 4 \cdot K_p}{K_v^2 \cdot T^2}, \quad 1 &amp;lt; \frac{8}{K_v^2 \cdot T^2}, \quad K_v^2 &amp;lt; \frac{8}{T^2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Окончательно,&lt;br /&gt;
:&amp;lt;math&amp;gt;K_v &amp;lt; \frac{2\sqrt{2}}{T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
При подстановке значения &amp;lt;math&amp;gt;T = 0.04&amp;lt;/math&amp;gt;, получается, что &amp;lt;math&amp;gt;K_v &amp;lt; 70&amp;lt;/math&amp;gt;. В реальных условиях эти пределы взяты еще меньше, для защиты от граничных случаев. Конкретно, &amp;lt;math&amp;gt;K_p&amp;lt;/math&amp;gt; по-умолчанию не может превышать 50, а &amp;lt;math&amp;gt;K_v&amp;lt;/math&amp;gt; — 30&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
[20:40:39] &amp;lt;droot@deeptown.org&amp;gt; так&lt;br /&gt;
[20:40:44] &amp;lt;droot@deeptown.org&amp;gt; а теперь - самое веселое&lt;br /&gt;
[20:40:51] &amp;lt;droot@deeptown.org&amp;gt; все то же самое, но только для вращения =)&lt;br /&gt;
[20:46:32] &amp;lt;korvin&amp;gt; мде..&lt;br /&gt;
[20:46:56] &amp;lt;droot@deeptown.org&amp;gt; там почти то же самое&lt;br /&gt;
[20:47:00] &amp;lt;korvin&amp;gt; ну вообще там не должно быть сильно сложно&lt;br /&gt;
[20:47:02] &amp;lt;korvin&amp;gt; то же самое по сути&lt;br /&gt;
[20:47:09] &amp;lt;droot@deeptown.org&amp;gt; т.е. плоская задача там будет точно такой же&lt;br /&gt;
[20:47:24] &amp;lt;droot@deeptown.org&amp;gt; только не y(t), а fi(t) - угол от времени&lt;br /&gt;
[20:48:03] &amp;lt;droot@deeptown.org&amp;gt; я вот не могу сообразить, что будет являться трехмерным представлением этого угла&lt;br /&gt;
[20:48:37] &amp;lt;korvin&amp;gt; в смысле?&lt;br /&gt;
[20:49:14] &amp;lt;droot@deeptown.org&amp;gt; ну вот в случае движения, от нашей задачи можно легко перейти к трехмерной, просто взяв не y(t), а r(t) - вектор координаты&lt;br /&gt;
[20:49:18] &amp;lt;droot@deeptown.org&amp;gt; мм..&lt;br /&gt;
[20:49:23] &amp;lt;droot@deeptown.org&amp;gt; ну точнее не совсем так&lt;br /&gt;
[20:49:27] &amp;lt;droot@deeptown.org&amp;gt; там же надо разность брать&lt;br /&gt;
[20:49:32] &amp;lt;droot@deeptown.org&amp;gt; а, ну да&lt;br /&gt;
[20:49:44] &amp;lt;droot@deeptown.org&amp;gt; т.е. вместо y(t) мы пишем разность векторов между сервером и клиентом&lt;br /&gt;
[20:49:45] &amp;lt;korvin&amp;gt; ну там вроде же просто 3 угла, которые можно точно так же линейно интерполировать&lt;br /&gt;
[20:50:45] &amp;lt;droot@deeptown.org&amp;gt; Vx - это модуль серверной скорости&lt;br /&gt;
[20:50:58] &amp;lt;droot@deeptown.org&amp;gt; ну а все остальное понятно&lt;br /&gt;
[20:51:29] &amp;lt;droot@deeptown.org&amp;gt; что же касается углов&lt;br /&gt;
[20:51:41] &amp;lt;droot@deeptown.org&amp;gt; ну если посмотреть на задачу с практической точки зрения&lt;br /&gt;
[20:51:50] &amp;lt;droot@deeptown.org&amp;gt; т.е. у нас есть два кватерниона&lt;br /&gt;
[20:53:24] &amp;lt;droot@deeptown.org&amp;gt; надо сообразить, что будет являться кватернионом вращения из одного положения во второе&lt;br /&gt;
[20:53:50] &amp;lt;korvin&amp;gt; в смысле что будет?&lt;br /&gt;
[20:54:12] &amp;lt;korvin&amp;gt; м... может проще представить кватернион в виде косинусов и дальше по частям?&lt;br /&gt;
[20:54:21] &amp;lt;korvin&amp;gt; покомпонентно в смысле&lt;br /&gt;
[20:54:23] &amp;lt;droot@deeptown.org&amp;gt; это долго считать&lt;br /&gt;
[20:59:55] &amp;lt;droot@deeptown.org&amp;gt; мм ну вообще все понятно&lt;br /&gt;
[21:00:19] &amp;lt;droot@deeptown.org&amp;gt; если сумма вращений задается кватернионом Q = q2 * q1&lt;br /&gt;
[21:00:47] &amp;lt;droot@deeptown.org&amp;gt; то разность вращений будет q2 = Q * q1^(-1) = Q * q1'&lt;br /&gt;
[21:01:36] &amp;lt;droot@deeptown.org&amp;gt; т.е. мы легко можем посчитать кватернион, который является разностью между клиентским и серверным вращениями&lt;br /&gt;
[21:03:54] &amp;lt;droot@deeptown.org&amp;gt; для того, чтобы повернуть тело этим кватернионом, нам нужно приложить к нему момент вращения, направление которого также можно посчитать&lt;br /&gt;
[21:05:56] &amp;lt;droot@deeptown.org&amp;gt; а зависеть он будет от тех же модуля серверной угловой скорости, собсно кватерниона разности, момента вращения, ну и соответственно некоторого коэффициента&lt;br /&gt;
[21:08:54] &amp;lt;droot@deeptown.org&amp;gt; ну а для стабилизации разности угловых скоростей все элементарно: момент вращения будет просто пропорционален разности векторов угловых скоростей (ну и направлен вдоль вектора этой разности)&lt;br /&gt;
[21:11:22] &amp;lt;korvin&amp;gt; так, ну это понятно&lt;br /&gt;
[21:11:32] &amp;lt;korvin&amp;gt; а с перерегулированием что делать?&lt;br /&gt;
[21:11:37] &amp;lt;korvin&amp;gt; ну то есть если перестараемся&lt;br /&gt;
[21:11:41] &amp;lt;droot@deeptown.org&amp;gt; (я вот щас мысленно пытаюсь себе это представить и думаю нсчет вектора разности...)&lt;br /&gt;
[21:12:44] &amp;lt;droot@deeptown.org&amp;gt; там собсно соотношение этих коэффициентов точно такое же должно получиться&lt;br /&gt;
[21:13:34] &amp;lt;droot@deeptown.org&amp;gt; т.е. W &amp;lt; Kw^2 / (4*Kr)&lt;br /&gt;
[21:42:36] &amp;lt;droot@deeptown.org&amp;gt; хочешь почитать веселую книжку? =)&lt;br /&gt;
[21:43:09] &amp;lt;droot@deeptown.org&amp;gt; я тут с аленкой попробовал проконсультироваться, и она мне оч посоветовала =) ландау-лифшиц &amp;quot;механика&amp;quot; называется =)&lt;br /&gt;
[21:55:38] &amp;lt;droot@deeptown.org&amp;gt; вообще, вот что до ограничений сверху для этих всех коэффициентов - я думаю, что надо просто взять некую константу - скажем, 30 - и ей ограничиться&lt;br /&gt;
[21:55:53] &amp;lt;droot@deeptown.org&amp;gt; т.е. Kv &amp;lt; 30&lt;br /&gt;
[21:56:10] &amp;lt;droot@deeptown.org&amp;gt; ну, для Kp можно ограничение чуть больше - скажем, Kp &amp;lt; 50&lt;br /&gt;
[21:58:57] &amp;lt;droot@deeptown.org&amp;gt; мм. а вообще, я бы даже не так сделал&lt;br /&gt;
[21:59:22] &amp;lt;droot@deeptown.org&amp;gt; мне кажется что параметризовать надо не через Kp и Kv, а через Vx и Kp, а уже Kv выражать через них&lt;br /&gt;
[21:59:36] &amp;lt;korvin&amp;gt; мм&lt;br /&gt;
[21:59:39] &amp;lt;korvin&amp;gt; а смысл?&lt;br /&gt;
[21:59:41] &amp;lt;droot@deeptown.org&amp;gt; (ну т.е. Vx - это максимальная скорость)&lt;br /&gt;
[21:59:50] &amp;lt;droot@deeptown.org&amp;gt; а это более понятные пользователю числа&lt;br /&gt;
[22:01:30] &amp;lt;droot@deeptown.org&amp;gt; хотя... ладно, фиг с ним, пусть будет напрямую&lt;br /&gt;
[22:01:40] &amp;lt;droot@deeptown.org&amp;gt; надо еще подумать, какие значения по-умолчанию лучше всего взять&lt;br /&gt;
[22:01:59] &amp;lt;droot@deeptown.org&amp;gt; ну Vx видимо надо брать где-то 10 как раз - это 36 км/ч&lt;br /&gt;
[22:02:22] &amp;lt;korvin&amp;gt; 10 м/с не жирно ли?&lt;br /&gt;
[22:02:24] &amp;lt;droot@deeptown.org&amp;gt; при большей уже вряд ли будут заметны эти силы&lt;br /&gt;
[22:02:55] &amp;lt;droot@deeptown.org&amp;gt; ну 36 км/ч - это где-то как раз граница воспринимаемых скоростей имхо&lt;br /&gt;
[22:04:02] &amp;lt;droot@deeptown.org&amp;gt; Kv предлагаю взять равным где-то 20&lt;br /&gt;
[22:04:46] &amp;lt;droot@deeptown.org&amp;gt; при этом будет хороший запас до сваливания из-за шага рассчета, но и время стабилизации будет достаточно малым&lt;br /&gt;
[22:04:55] &amp;lt;droot@deeptown.org&amp;gt; ну а Kp щас посчитаем&lt;br /&gt;
[22:05:11] &amp;lt;droot@deeptown.org&amp;gt; Vx = Kv^2 / (4*Kp)&lt;br /&gt;
[22:05:26] &amp;lt;droot@deeptown.org&amp;gt; Kp = Vx * 4 / Kv^2&lt;br /&gt;
[22:05:37] &amp;lt;droot@deeptown.org&amp;gt; тьфу&lt;br /&gt;
[22:05:57] &amp;lt;droot@deeptown.org&amp;gt; Kp = Kv&amp;amp;2 / (Vx*4)&lt;br /&gt;
[22:06:31] &amp;lt;droot@deeptown.org&amp;gt; Kp = 20^2 / 40 = 10&lt;br /&gt;
[22:06:40] &amp;lt;droot@deeptown.org&amp;gt; ну, вполне себе круглые числа =)&lt;br /&gt;
[22:06:48] &amp;lt;droot@deeptown.org&amp;gt; Vx = 10, Kp = 10, Kv = 20&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%81%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8</id>
		<title>Алгоритм синхронизации</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%81%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8"/>
				<updated>2008-10-24T17:12:16Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* Построение сплайна */&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;
:&amp;lt;math&amp;gt;s(t_i) = f(t_i), \quad s'(t_i) = f'(t_i)\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Уравнения сплайна:&lt;br /&gt;
:&amp;lt;math&amp;gt;s(t) = a + bt + ct^2 + dt^3\!&amp;lt;/math&amp;gt;&lt;br /&gt;
:&amp;lt;math&amp;gt;s'(t) = b + 2ct + 3dt^2\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Для нахождения коэффициентов &amp;lt;math&amp;gt;a, b, c, d&amp;lt;/math&amp;gt; записываем систему уравнений:&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
a + bt_0 + ct_0^2 + dt_0^3 = f(t_0) \\&lt;br /&gt;
a + bt_1 + ct_1^2 + dt_1^3 = f(t_1) \\&lt;br /&gt;
b + 2ct_0 + 3dt_0^2 = f'(t_0) \\&lt;br /&gt;
b + 2ct_1 + 3dt_1^2 = f'(t_1)&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Подставляем известные значения в правой части системы (даны по условию):&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
a + bt_0 + ct_0^2 + dt_0^3 = x_0 \\&lt;br /&gt;
a + bt_1 + ct_1^2 + dt_1^3 = x_1 \\&lt;br /&gt;
b + 2ct_0 + 3dt_0^2 = v_0 \\&lt;br /&gt;
b + 2ct_1 + 3dt_1^2 = v_1&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Поскольку сплайн не зависит от конкретных значений &amp;lt;math&amp;gt;t_0&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;t_1&amp;lt;/math&amp;gt;, положим &amp;lt;math&amp;gt;t_0 = 0&amp;lt;/math&amp;gt;, а &amp;lt;math&amp;gt;t_1 = t&amp;lt;/math&amp;gt;. В результате, пара уравнений становится тривиальной:&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
a = x_0 \\&lt;br /&gt;
a + bt + ct^2 + dt^3 = x_1 \\&lt;br /&gt;
b = v_0 \\&lt;br /&gt;
b + 2ct + 3dt^2 = v_1&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Заменяем в оставшихся уравнениях известные теперь коэффициенты и получаем конечную систему:&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
x_0 + v_0t + ct^2 + dt^3 = x_1 \\&lt;br /&gt;
v_0 + 2ct + 3dt^2 = v_1&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
После нехитрых манипуляций, получаем выражения для оставшихся коэффициентов:&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
c = \frac{3x_1 - 3x_0 - 2v_0t - v_1t}{t^2} \\&lt;br /&gt;
d = \frac{v_1t - 2x_1 + 2x_0 + v_ot}{t^3}&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ниже представлены графики оригинальной функции с наложенным на них графиком сплайна, построенного по точкам. Парабола и экспонента построены по фиксированному набору точек (-2.5, -2, -0.5, 0.5, 2, 2.5). Синусоида построена по точкам с интервалом 0.05.&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
Изображение:Exp.gif|Экспонента&lt;br /&gt;
Изображение:Parabola2.gif|Парабола&lt;br /&gt;
Изображение:Sin.gif|Синус&lt;br /&gt;
&amp;lt;/gallery&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;
Коррекция осуществляется путем приложения сторонней силы к движущемуся телу так, чтобы &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;
Осталось убедиться, что сумма этих сил действительно стабилизирует траекторию движения объекта, не приведет к колебаниям, и найти оптимальные значения для коэффициентов двух сил.&lt;br /&gt;
&lt;br /&gt;
Чтобы упростить себе жизнь, рассмотрим двумерный случай. Пусть серверная траектория тела совпадает с осью X; клиентская траектория — параллельна этой оси и находится от нее на расстоянии, равном H. В нулевой момент времени тело находится в нуле по оси X как на клиентской, так и на серверной траекториях.&lt;br /&gt;
&lt;br /&gt;
Пусть и серверная, и клиентская точки имеют горизонтальную скорость &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt;, а по вертикальной оси они неподвижны. Никаких прочих сил на объект не действует. Поскольку никаких сил по горизонтали не действует, мы будем рассматривать только движение по оси y.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Сила коррекции высоты, по такой модели, будет направлена &amp;quot;вниз&amp;quot; на эту точку и будет равна: &lt;br /&gt;
:&amp;lt;math&amp;gt;F_p = - K_p \cdot y(t) \cdot V_x \cdot m&amp;lt;/math&amp;gt;&lt;br /&gt;
где &amp;lt;math&amp;gt;y&amp;lt;/math&amp;gt; — это высота точки и &lt;br /&gt;
:&amp;lt;math&amp;gt;y(0) = H\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Множитель &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; мы добавляем специально, чтобы уменьшить влияние силы коррекции на малых скоростях (иначе еле движущееся тело будет менять свое положение заметными глазу рывками).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Сила коррекции вертикальной скорости точки:&lt;br /&gt;
:&amp;lt;math&amp;gt;F_v = - K_v \cdot V_y(t) \cdot m&amp;lt;/math&amp;gt;&lt;br /&gt;
и &lt;br /&gt;
:&amp;lt;math&amp;gt;V_y(0) = 0\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Известно, что скорость — это производная координаты по времени:&lt;br /&gt;
:&amp;lt;math&amp;gt;V_y(t) = \frac{\partial y(t)}{\partial t}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Соответственно, сила, которая действует на объект:&lt;br /&gt;
:&amp;lt;math&amp;gt;F(t) = m \cdot y''(t) = F_p + F_v = - K_p \cdot y(t) \cdot V_x \cdot m - K_v \cdot V_y(t) \cdot m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;F - F_p - F_v = 0\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Разделив на массу, и записав уравнение в дифференциальной форме, получим:&lt;br /&gt;
:&amp;lt;math&amp;gt;y''(t) + K_v \cdot y'(t) + K_p \cdot y(t) \cdot Vx = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Перепишем параметрически:&lt;br /&gt;
:&amp;lt;math&amp;gt;y''(t) + A \cdot y'(t) + B \cdot y(t) = 0\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Характеристическое уравнение:&lt;br /&gt;
:&amp;lt;math&amp;gt;\lambda^2 + A \cdot \lambda + B = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Дискриминант характеристического уравнения:&lt;br /&gt;
:&amp;lt;math&amp;gt;D = A^2 - 4 \cdot B = K_v^2 - 4 \cdot K_p \cdot V_x&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для исключения колебательного процесса, необходимо условие &amp;lt;math&amp;gt;D \geqslant 0&amp;lt;/math&amp;gt;. Следовательно:&lt;br /&gt;
:&amp;lt;math&amp;gt;K_v^2 - 4 \cdot K_p \cdot V_x \geqslant 0&amp;lt;/math&amp;gt;&lt;br /&gt;
:&amp;lt;math&amp;gt;K_v^2 \geqslant 4 \cdot K_p \cdot V_x, \quad V_x \leqslant \frac{K_v^2}{4 \cdot K_p}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Видно, что если &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; будет больше чем эта дробь, то возникнут колебания (нарушается условие &amp;lt;math&amp;gt;D \geqslant 0&amp;lt;/math&amp;gt;). Поэтому, при малых скоростях используется само значение &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt;, а когда &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; численно становится больше этой дроби, следует заменять ее на эту дробь (ограничение сверху).&lt;br /&gt;
&lt;br /&gt;
В конечном счете, коэффициенты &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; выражаются как&lt;br /&gt;
:&amp;lt;math&amp;gt;\alpha_{1,2} = \frac{-K_v \pm \sqrt{D}}{2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Далее, найдем коэффициенты &amp;lt;math&amp;gt;C_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;C_2&amp;lt;/math&amp;gt;: &lt;br /&gt;
:&amp;lt;math&amp;gt;y(t) = C_1 \cdot e^{\alpha_1 t} + C_2 \cdot e^{\alpha_2 t}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Зная начальные условия  &amp;lt;math&amp;gt;y(0) = H&amp;lt;/math&amp;gt; (начальное расстояние между объектами) и &amp;lt;math&amp;gt;y'(t) = 0&amp;lt;/math&amp;gt; получаем уравнение:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_1 \cdot e^{\alpha_1 \cdot 0} + C_2 \cdot e^{\alpha_2 \cdot 0} = y(0) = H&amp;lt;/math&amp;gt; &lt;br /&gt;
следовательно &lt;br /&gt;
:&amp;lt;math&amp;gt;C_1 + C_2 = H\!&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из второго условия:&lt;br /&gt;
:&amp;lt;math&amp;gt;\alpha_1 \cdot C_1 \cdot e^{\alpha_1 \cdot 0} + \alpha_2 \cdot C_2 \cdot e^{\alpha_2 \cdot 0} = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
:&amp;lt;math&amp;gt;\alpha_1 \cdot C_1 + \alpha_2 \cdot C_2 = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Получаем систему следующих уравнений:&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
C_1 + C_2 = H \\&lt;br /&gt;
\alpha_1 \cdot C_1 + \alpha_2 \cdot C_2 = 0&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Решая систему относительно &amp;lt;math&amp;gt;C_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;C_2&amp;lt;/math&amp;gt;, получаем&lt;br /&gt;
:&amp;lt;math&amp;gt;C_{1,2} = \left ( \frac{1}{2} \pm \frac{K_v}{\sqrt{D}} \right ) \cdot H&amp;lt;/math&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;quot;между&amp;quot; коррекциями тело предоставлено само себе, оно и будет двигаться в указанную ему сторону. В худшем случае, при больших и плохо подобранных параметрах, уже после первого корректирующего воздействия, тело вылетит &amp;quot;за траекторию&amp;quot;, соответственно возникнут колебания (возможно даже возрастающие).&lt;br /&gt;
&lt;br /&gt;
Для избежания этого неприятного момента, попробуем оценить параметры и найти их &amp;quot;практический потолок&amp;quot;, с тем, чтобы не позволять пользователю задавать значения выходящие за границы.&lt;br /&gt;
&lt;br /&gt;
Итак, при моделировании, будем считать что в течение шага тело движется по прямой. Соответственно, сила, которая будет действовать на тело в течение первого шага, т.е. времени &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, будет равна &lt;br /&gt;
:&amp;lt;math&amp;gt;F_p = - K_p \cdot V_x \cdot H \cdot m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Соответственно, в течение первого шага тело будет двигаться с ускорением &lt;br /&gt;
:&amp;lt;math&amp;gt;a = - K_p \cdot Vx \cdot H&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Условие стабилизации — расстояние, которое преодолеет тело за первый шаг должно быть меньше &amp;lt;math&amp;gt;H&amp;lt;/math&amp;gt;:&lt;br /&gt;
:&amp;lt;math&amp;gt;K_p \cdot V_x \cdot H \cdot \frac{T^2}{2} &amp;lt; H, \quad K_p \cdot V_x \cdot T^2 &amp;lt; 2, \quad K_p &amp;lt; \frac{2}{V_x \cdot {T^2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Левая часть неравенства будет минимальной в случае, когда &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; максимальна, т.е. равна &amp;lt;math&amp;gt;\tfrac{K_v^2}{4 \cdot K_p}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Это означает, что в том случае когда модуль скорости тела меньше чем указанное значение, то коррекция происходить гладко; когда больше — в формуле для силы стабилизации положения &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; заменяется на &amp;lt;math&amp;gt;\tfrac{K_v^2}{4 \cdot K_p}&amp;lt;/math&amp;gt;. Объяснение было дано выше, при оценке дискриминанта характеристического уравнения.&lt;br /&gt;
&lt;br /&gt;
Из этого следует, что чтобы действительно сделать невидимым действие нашей силы на малых скоростях, необходимо, чтобы значение &amp;lt;math&amp;gt;\tfrac{K_v^2}{4 \cdot K_p}&amp;lt;/math&amp;gt; было бы достаточно большим. Мы взяли его по-умолчанию равным 10, но это значение можно бдет менять в свойствах каждого конкретного объекта.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Осталось только численно оценить коэффициенты &amp;lt;math&amp;gt;K_p&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;K_v&amp;lt;/math&amp;gt;. Для &amp;lt;math&amp;gt;K_p&amp;lt;/math&amp;gt; конкретное значение получается, если подставить в условие &lt;br /&gt;
:&amp;lt;math&amp;gt;K_p &amp;lt; \frac{2}{V_x \cdot T^2}&amp;lt;/math&amp;gt;&lt;br /&gt;
значения &amp;lt;math&amp;gt;V_x = 10&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;T = 0.04&amp;lt;/math&amp;gt;. Получается, что &amp;lt;math&amp;gt;K_p &amp;lt; 125&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Для нахождения &amp;lt;math&amp;gt;K_v&amp;lt;/math&amp;gt; вместо &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; необходимо подставить наибольшее возможное для нее значение &amp;lt;math&amp;gt;\tfrac{K_v^2}{4 \cdot K_p}&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;K_p &amp;lt; \frac{2}{\frac{K_v^2}{4 \cdot K_p} \cdot T^2}, \quad K_p &amp;lt; \frac{2 \cdot 4 \cdot K_p}{K_v^2 \cdot T^2}, \quad 1 &amp;lt; \frac{8}{K_v^2 \cdot T^2}, \quad K_v^2 &amp;lt; \frac{8}{T^2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Окончательно,&lt;br /&gt;
:&amp;lt;math&amp;gt;K_v &amp;lt; \frac{2\sqrt{2}}{T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
При подстановке значения &amp;lt;math&amp;gt;T = 0.04&amp;lt;/math&amp;gt;, получается, что &amp;lt;math&amp;gt;K_v &amp;lt; 70&amp;lt;/math&amp;gt;. В реальных условиях эти пределы взяты еще меньше, для защиты от граничных случаев. Конкретно, &amp;lt;math&amp;gt;K_p&amp;lt;/math&amp;gt; по-умолчанию не может превышать 50, а &amp;lt;math&amp;gt;K_v&amp;lt;/math&amp;gt; — 30&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
[20:40:39] &amp;lt;droot@deeptown.org&amp;gt; так&lt;br /&gt;
[20:40:44] &amp;lt;droot@deeptown.org&amp;gt; а теперь - самое веселое&lt;br /&gt;
[20:40:51] &amp;lt;droot@deeptown.org&amp;gt; все то же самое, но только для вращения =)&lt;br /&gt;
[20:46:32] &amp;lt;korvin&amp;gt; мде..&lt;br /&gt;
[20:46:56] &amp;lt;droot@deeptown.org&amp;gt; там почти то же самое&lt;br /&gt;
[20:47:00] &amp;lt;korvin&amp;gt; ну вообще там не должно быть сильно сложно&lt;br /&gt;
[20:47:02] &amp;lt;korvin&amp;gt; то же самое по сути&lt;br /&gt;
[20:47:09] &amp;lt;droot@deeptown.org&amp;gt; т.е. плоская задача там будет точно такой же&lt;br /&gt;
[20:47:24] &amp;lt;droot@deeptown.org&amp;gt; только не y(t), а fi(t) - угол от времени&lt;br /&gt;
[20:48:03] &amp;lt;droot@deeptown.org&amp;gt; я вот не могу сообразить, что будет являться трехмерным представлением этого угла&lt;br /&gt;
[20:48:37] &amp;lt;korvin&amp;gt; в смысле?&lt;br /&gt;
[20:49:14] &amp;lt;droot@deeptown.org&amp;gt; ну вот в случае движения, от нашей задачи можно легко перейти к трехмерной, просто взяв не y(t), а r(t) - вектор координаты&lt;br /&gt;
[20:49:18] &amp;lt;droot@deeptown.org&amp;gt; мм..&lt;br /&gt;
[20:49:23] &amp;lt;droot@deeptown.org&amp;gt; ну точнее не совсем так&lt;br /&gt;
[20:49:27] &amp;lt;droot@deeptown.org&amp;gt; там же надо разность брать&lt;br /&gt;
[20:49:32] &amp;lt;droot@deeptown.org&amp;gt; а, ну да&lt;br /&gt;
[20:49:44] &amp;lt;droot@deeptown.org&amp;gt; т.е. вместо y(t) мы пишем разность векторов между сервером и клиентом&lt;br /&gt;
[20:49:45] &amp;lt;korvin&amp;gt; ну там вроде же просто 3 угла, которые можно точно так же линейно интерполировать&lt;br /&gt;
[20:50:45] &amp;lt;droot@deeptown.org&amp;gt; Vx - это модуль серверной скорости&lt;br /&gt;
[20:50:58] &amp;lt;droot@deeptown.org&amp;gt; ну а все остальное понятно&lt;br /&gt;
[20:51:29] &amp;lt;droot@deeptown.org&amp;gt; что же касается углов&lt;br /&gt;
[20:51:41] &amp;lt;droot@deeptown.org&amp;gt; ну если посмотреть на задачу с практической точки зрения&lt;br /&gt;
[20:51:50] &amp;lt;droot@deeptown.org&amp;gt; т.е. у нас есть два кватерниона&lt;br /&gt;
[20:53:24] &amp;lt;droot@deeptown.org&amp;gt; надо сообразить, что будет являться кватернионом вращения из одного положения во второе&lt;br /&gt;
[20:53:50] &amp;lt;korvin&amp;gt; в смысле что будет?&lt;br /&gt;
[20:54:12] &amp;lt;korvin&amp;gt; м... может проще представить кватернион в виде косинусов и дальше по частям?&lt;br /&gt;
[20:54:21] &amp;lt;korvin&amp;gt; покомпонентно в смысле&lt;br /&gt;
[20:54:23] &amp;lt;droot@deeptown.org&amp;gt; это долго считать&lt;br /&gt;
[20:59:55] &amp;lt;droot@deeptown.org&amp;gt; мм ну вообще все понятно&lt;br /&gt;
[21:00:19] &amp;lt;droot@deeptown.org&amp;gt; если сумма вращений задается кватернионом Q = q2 * q1&lt;br /&gt;
[21:00:47] &amp;lt;droot@deeptown.org&amp;gt; то разность вращений будет q2 = Q * q1^(-1) = Q * q1'&lt;br /&gt;
[21:01:36] &amp;lt;droot@deeptown.org&amp;gt; т.е. мы легко можем посчитать кватернион, который является разностью между клиентским и серверным вращениями&lt;br /&gt;
[21:03:54] &amp;lt;droot@deeptown.org&amp;gt; для того, чтобы повернуть тело этим кватернионом, нам нужно приложить к нему момент вращения, направление которого также можно посчитать&lt;br /&gt;
[21:05:56] &amp;lt;droot@deeptown.org&amp;gt; а зависеть он будет от тех же модуля серверной угловой скорости, собсно кватерниона разности, момента вращения, ну и соответственно некоторого коэффициента&lt;br /&gt;
[21:08:54] &amp;lt;droot@deeptown.org&amp;gt; ну а для стабилизации разности угловых скоростей все элементарно: момент вращения будет просто пропорционален разности векторов угловых скоростей (ну и направлен вдоль вектора этой разности)&lt;br /&gt;
[21:11:22] &amp;lt;korvin&amp;gt; так, ну это понятно&lt;br /&gt;
[21:11:32] &amp;lt;korvin&amp;gt; а с перерегулированием что делать?&lt;br /&gt;
[21:11:37] &amp;lt;korvin&amp;gt; ну то есть если перестараемся&lt;br /&gt;
[21:11:41] &amp;lt;droot@deeptown.org&amp;gt; (я вот щас мысленно пытаюсь себе это представить и думаю нсчет вектора разности...)&lt;br /&gt;
[21:12:44] &amp;lt;droot@deeptown.org&amp;gt; там собсно соотношение этих коэффициентов точно такое же должно получиться&lt;br /&gt;
[21:13:34] &amp;lt;droot@deeptown.org&amp;gt; т.е. W &amp;lt; Kw^2 / (4*Kr)&lt;br /&gt;
[21:42:36] &amp;lt;droot@deeptown.org&amp;gt; хочешь почитать веселую книжку? =)&lt;br /&gt;
[21:43:09] &amp;lt;droot@deeptown.org&amp;gt; я тут с аленкой попробовал проконсультироваться, и она мне оч посоветовала =) ландау-лифшиц &amp;quot;механика&amp;quot; называется =)&lt;br /&gt;
[21:55:38] &amp;lt;droot@deeptown.org&amp;gt; вообще, вот что до ограничений сверху для этих всех коэффициентов - я думаю, что надо просто взять некую константу - скажем, 30 - и ей ограничиться&lt;br /&gt;
[21:55:53] &amp;lt;droot@deeptown.org&amp;gt; т.е. Kv &amp;lt; 30&lt;br /&gt;
[21:56:10] &amp;lt;droot@deeptown.org&amp;gt; ну, для Kp можно ограничение чуть больше - скажем, Kp &amp;lt; 50&lt;br /&gt;
[21:58:57] &amp;lt;droot@deeptown.org&amp;gt; мм. а вообще, я бы даже не так сделал&lt;br /&gt;
[21:59:22] &amp;lt;droot@deeptown.org&amp;gt; мне кажется что параметризовать надо не через Kp и Kv, а через Vx и Kp, а уже Kv выражать через них&lt;br /&gt;
[21:59:36] &amp;lt;korvin&amp;gt; мм&lt;br /&gt;
[21:59:39] &amp;lt;korvin&amp;gt; а смысл?&lt;br /&gt;
[21:59:41] &amp;lt;droot@deeptown.org&amp;gt; (ну т.е. Vx - это максимальная скорость)&lt;br /&gt;
[21:59:50] &amp;lt;droot@deeptown.org&amp;gt; а это более понятные пользователю числа&lt;br /&gt;
[22:01:30] &amp;lt;droot@deeptown.org&amp;gt; хотя... ладно, фиг с ним, пусть будет напрямую&lt;br /&gt;
[22:01:40] &amp;lt;droot@deeptown.org&amp;gt; надо еще подумать, какие значения по-умолчанию лучше всего взять&lt;br /&gt;
[22:01:59] &amp;lt;droot@deeptown.org&amp;gt; ну Vx видимо надо брать где-то 10 как раз - это 36 км/ч&lt;br /&gt;
[22:02:22] &amp;lt;korvin&amp;gt; 10 м/с не жирно ли?&lt;br /&gt;
[22:02:24] &amp;lt;droot@deeptown.org&amp;gt; при большей уже вряд ли будут заметны эти силы&lt;br /&gt;
[22:02:55] &amp;lt;droot@deeptown.org&amp;gt; ну 36 км/ч - это где-то как раз граница воспринимаемых скоростей имхо&lt;br /&gt;
[22:04:02] &amp;lt;droot@deeptown.org&amp;gt; Kv предлагаю взять равным где-то 20&lt;br /&gt;
[22:04:46] &amp;lt;droot@deeptown.org&amp;gt; при этом будет хороший запас до сваливания из-за шага рассчета, но и время стабилизации будет достаточно малым&lt;br /&gt;
[22:04:55] &amp;lt;droot@deeptown.org&amp;gt; ну а Kp щас посчитаем&lt;br /&gt;
[22:05:11] &amp;lt;droot@deeptown.org&amp;gt; Vx = Kv^2 / (4*Kp)&lt;br /&gt;
[22:05:26] &amp;lt;droot@deeptown.org&amp;gt; Kp = Vx * 4 / Kv^2&lt;br /&gt;
[22:05:37] &amp;lt;droot@deeptown.org&amp;gt; тьфу&lt;br /&gt;
[22:05:57] &amp;lt;droot@deeptown.org&amp;gt; Kp = Kv&amp;amp;2 / (Vx*4)&lt;br /&gt;
[22:06:31] &amp;lt;droot@deeptown.org&amp;gt; Kp = 20^2 / 40 = 10&lt;br /&gt;
[22:06:40] &amp;lt;droot@deeptown.org&amp;gt; ну, вполне себе круглые числа =)&lt;br /&gt;
[22:06:48] &amp;lt;droot@deeptown.org&amp;gt; Vx = 10, Kp = 10, Kv = 20&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%81%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8</id>
		<title>Алгоритм синхронизации</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%81%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8"/>
				<updated>2008-10-24T17:07:42Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* Механизм коррекции ошибки */&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;
:&amp;lt;math&amp;gt;s(t_i) = f(t_i), \quad s'(t_i) = f'(t_i)\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Уравнения сплайна:&lt;br /&gt;
:&amp;lt;math&amp;gt;s(t) = a + bt + ct^2 + dt^3\!&amp;lt;/math&amp;gt;&lt;br /&gt;
:&amp;lt;math&amp;gt;s'(t) = b + 2ct + 3dt^2\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Для нахождения коэффициентов &amp;lt;math&amp;gt;a, b, c, d&amp;lt;/math&amp;gt; записываем систему уравнений:&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
a + bt_0 + ct_0^2 + dt_0^3 = f(t_0) \\&lt;br /&gt;
a + bt_1 + ct_1^2 + dt_1^3 = f(t_1) \\&lt;br /&gt;
b + 2ct_0 + 3dt_0^2 = f'(t_0) \\&lt;br /&gt;
b + 2ct_1 + 3dt_1^2 = f'(t_1)&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Подставляем известные значения в правой части системы (даны по условию):&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
a + bt_0 + ct_0^2 + dt_0^3 = x_0 \\&lt;br /&gt;
a + bt_1 + ct_1^2 + dt_1^3 = x_1 \\&lt;br /&gt;
b + 2ct_0 + 3dt_0^2 = v_0 \\&lt;br /&gt;
b + 2ct_1 + 3dt_1^2 = v_1&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Поскольку сплайн не зависит от конкретных значений &amp;lt;math&amp;gt;t_0&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;t_1&amp;lt;/math&amp;gt;, положим &amp;lt;math&amp;gt;t_0 = 0&amp;lt;/math&amp;gt;, а &amp;lt;math&amp;gt;t_1 = t&amp;lt;/math&amp;gt;. В результате, пара уравнений становится тривиальной:&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
a = x_0 \\&lt;br /&gt;
a + bt_1 + ct_1^2 + dt_1^3 = x_1 \\&lt;br /&gt;
b = v_0 \\&lt;br /&gt;
b + 2ct_1 + 3dt_1^2 = v_1&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Заменяем в оставшихся уравнениях известные теперь коэффициенты и получаем конечную систему:&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
x_0 + v_0t_1 + ct_1^2 + dt_1^3 = x_1 \\&lt;br /&gt;
v_0 + 2ct_1 + 3dt_1^2 = v_1&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
После нехитрых манипуляций, получаем выражения для оставшихся коэффициентов:&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
c = \frac{3x_1 - 3x_0 - 2v_0t - v_1t}{t^2} \\&lt;br /&gt;
d = \frac{v_1t - 2x_1 + 2x_0 + v_ot}{t^3}&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ниже представлены графики оригинальной функции с наложенным на них графиком сплайна, построенного по точкам. Парабола и экспонента построены по фиксированному набору точек (-2.5, -2, -0.5, 0.5, 2, 2.5). Синусоида построена по точкам с интервалом 0.05.&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
Изображение:Exp.gif|Экспонента&lt;br /&gt;
Изображение:Parabola2.gif|Парабола&lt;br /&gt;
Изображение:Sin.gif|Синус&lt;br /&gt;
&amp;lt;/gallery&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;
Коррекция осуществляется путем приложения сторонней силы к движущемуся телу так, чтобы &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;
Осталось убедиться, что сумма этих сил действительно стабилизирует траекторию движения объекта, не приведет к колебаниям, и найти оптимальные значения для коэффициентов двух сил.&lt;br /&gt;
&lt;br /&gt;
Чтобы упростить себе жизнь, рассмотрим двумерный случай. Пусть серверная траектория тела совпадает с осью X; клиентская траектория — параллельна этой оси и находится от нее на расстоянии, равном H. В нулевой момент времени тело находится в нуле по оси X как на клиентской, так и на серверной траекториях.&lt;br /&gt;
&lt;br /&gt;
Пусть и серверная, и клиентская точки имеют горизонтальную скорость &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt;, а по вертикальной оси они неподвижны. Никаких прочих сил на объект не действует. Поскольку никаких сил по горизонтали не действует, мы будем рассматривать только движение по оси y.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Сила коррекции высоты, по такой модели, будет направлена &amp;quot;вниз&amp;quot; на эту точку и будет равна: &lt;br /&gt;
:&amp;lt;math&amp;gt;F_p = - K_p \cdot y(t) \cdot V_x \cdot m&amp;lt;/math&amp;gt;&lt;br /&gt;
где &amp;lt;math&amp;gt;y&amp;lt;/math&amp;gt; — это высота точки и &lt;br /&gt;
:&amp;lt;math&amp;gt;y(0) = H\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Множитель &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; мы добавляем специально, чтобы уменьшить влияние силы коррекции на малых скоростях (иначе еле движущееся тело будет менять свое положение заметными глазу рывками).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Сила коррекции вертикальной скорости точки:&lt;br /&gt;
:&amp;lt;math&amp;gt;F_v = - K_v \cdot V_y(t) \cdot m&amp;lt;/math&amp;gt;&lt;br /&gt;
и &lt;br /&gt;
:&amp;lt;math&amp;gt;V_y(0) = 0\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Известно, что скорость — это производная координаты по времени:&lt;br /&gt;
:&amp;lt;math&amp;gt;V_y(t) = \frac{\partial y(t)}{\partial t}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Соответственно, сила, которая действует на объект:&lt;br /&gt;
:&amp;lt;math&amp;gt;F(t) = m \cdot y''(t) = F_p + F_v = - K_p \cdot y(t) \cdot V_x \cdot m - K_v \cdot V_y(t) \cdot m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;F - F_p - F_v = 0\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Разделив на массу, и записав уравнение в дифференциальной форме, получим:&lt;br /&gt;
:&amp;lt;math&amp;gt;y''(t) + K_v \cdot y'(t) + K_p \cdot y(t) \cdot Vx = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Перепишем параметрически:&lt;br /&gt;
:&amp;lt;math&amp;gt;y''(t) + A \cdot y'(t) + B \cdot y(t) = 0\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Характеристическое уравнение:&lt;br /&gt;
:&amp;lt;math&amp;gt;\lambda^2 + A \cdot \lambda + B = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Дискриминант характеристического уравнения:&lt;br /&gt;
:&amp;lt;math&amp;gt;D = A^2 - 4 \cdot B = K_v^2 - 4 \cdot K_p \cdot V_x&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для исключения колебательного процесса, необходимо условие &amp;lt;math&amp;gt;D \geqslant 0&amp;lt;/math&amp;gt;. Следовательно:&lt;br /&gt;
:&amp;lt;math&amp;gt;K_v^2 - 4 \cdot K_p \cdot V_x \geqslant 0&amp;lt;/math&amp;gt;&lt;br /&gt;
:&amp;lt;math&amp;gt;K_v^2 \geqslant 4 \cdot K_p \cdot V_x, \quad V_x \leqslant \frac{K_v^2}{4 \cdot K_p}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Видно, что если &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; будет больше чем эта дробь, то возникнут колебания (нарушается условие &amp;lt;math&amp;gt;D \geqslant 0&amp;lt;/math&amp;gt;). Поэтому, при малых скоростях используется само значение &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt;, а когда &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; численно становится больше этой дроби, следует заменять ее на эту дробь (ограничение сверху).&lt;br /&gt;
&lt;br /&gt;
В конечном счете, коэффициенты &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; выражаются как&lt;br /&gt;
:&amp;lt;math&amp;gt;\alpha_{1,2} = \frac{-K_v \pm \sqrt{D}}{2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Далее, найдем коэффициенты &amp;lt;math&amp;gt;C_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;C_2&amp;lt;/math&amp;gt;: &lt;br /&gt;
:&amp;lt;math&amp;gt;y(t) = C_1 \cdot e^{\alpha_1 t} + C_2 \cdot e^{\alpha_2 t}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Зная начальные условия  &amp;lt;math&amp;gt;y(0) = H&amp;lt;/math&amp;gt; (начальное расстояние между объектами) и &amp;lt;math&amp;gt;y'(t) = 0&amp;lt;/math&amp;gt; получаем уравнение:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_1 \cdot e^{\alpha_1 \cdot 0} + C_2 \cdot e^{\alpha_2 \cdot 0} = y(0) = H&amp;lt;/math&amp;gt; &lt;br /&gt;
следовательно &lt;br /&gt;
:&amp;lt;math&amp;gt;C_1 + C_2 = H\!&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из второго условия:&lt;br /&gt;
:&amp;lt;math&amp;gt;\alpha_1 \cdot C_1 \cdot e^{\alpha_1 \cdot 0} + \alpha_2 \cdot C_2 \cdot e^{\alpha_2 \cdot 0} = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
:&amp;lt;math&amp;gt;\alpha_1 \cdot C_1 + \alpha_2 \cdot C_2 = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Получаем систему следующих уравнений:&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
C_1 + C_2 = H \\&lt;br /&gt;
\alpha_1 \cdot C_1 + \alpha_2 \cdot C_2 = 0&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Решая систему относительно &amp;lt;math&amp;gt;C_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;C_2&amp;lt;/math&amp;gt;, получаем&lt;br /&gt;
:&amp;lt;math&amp;gt;C_{1,2} = \left ( \frac{1}{2} \pm \frac{K_v}{\sqrt{D}} \right ) \cdot H&amp;lt;/math&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;quot;между&amp;quot; коррекциями тело предоставлено само себе, оно и будет двигаться в указанную ему сторону. В худшем случае, при больших и плохо подобранных параметрах, уже после первого корректирующего воздействия, тело вылетит &amp;quot;за траекторию&amp;quot;, соответственно возникнут колебания (возможно даже возрастающие).&lt;br /&gt;
&lt;br /&gt;
Для избежания этого неприятного момента, попробуем оценить параметры и найти их &amp;quot;практический потолок&amp;quot;, с тем, чтобы не позволять пользователю задавать значения выходящие за границы.&lt;br /&gt;
&lt;br /&gt;
Итак, при моделировании, будем считать что в течение шага тело движется по прямой. Соответственно, сила, которая будет действовать на тело в течение первого шага, т.е. времени &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, будет равна &lt;br /&gt;
:&amp;lt;math&amp;gt;F_p = - K_p \cdot V_x \cdot H \cdot m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Соответственно, в течение первого шага тело будет двигаться с ускорением &lt;br /&gt;
:&amp;lt;math&amp;gt;a = - K_p \cdot Vx \cdot H&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Условие стабилизации — расстояние, которое преодолеет тело за первый шаг должно быть меньше &amp;lt;math&amp;gt;H&amp;lt;/math&amp;gt;:&lt;br /&gt;
:&amp;lt;math&amp;gt;K_p \cdot V_x \cdot H \cdot \frac{T^2}{2} &amp;lt; H, \quad K_p \cdot V_x \cdot T^2 &amp;lt; 2, \quad K_p &amp;lt; \frac{2}{V_x \cdot {T^2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Левая часть неравенства будет минимальной в случае, когда &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; максимальна, т.е. равна &amp;lt;math&amp;gt;\tfrac{K_v^2}{4 \cdot K_p}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Это означает, что в том случае когда модуль скорости тела меньше чем указанное значение, то коррекция происходить гладко; когда больше — в формуле для силы стабилизации положения &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; заменяется на &amp;lt;math&amp;gt;\tfrac{K_v^2}{4 \cdot K_p}&amp;lt;/math&amp;gt;. Объяснение было дано выше, при оценке дискриминанта характеристического уравнения.&lt;br /&gt;
&lt;br /&gt;
Из этого следует, что чтобы действительно сделать невидимым действие нашей силы на малых скоростях, необходимо, чтобы значение &amp;lt;math&amp;gt;\tfrac{K_v^2}{4 \cdot K_p}&amp;lt;/math&amp;gt; было бы достаточно большим. Мы взяли его по-умолчанию равным 10, но это значение можно бдет менять в свойствах каждого конкретного объекта.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Осталось только численно оценить коэффициенты &amp;lt;math&amp;gt;K_p&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;K_v&amp;lt;/math&amp;gt;. Для &amp;lt;math&amp;gt;K_p&amp;lt;/math&amp;gt; конкретное значение получается, если подставить в условие &lt;br /&gt;
:&amp;lt;math&amp;gt;K_p &amp;lt; \frac{2}{V_x \cdot T^2}&amp;lt;/math&amp;gt;&lt;br /&gt;
значения &amp;lt;math&amp;gt;V_x = 10&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;T = 0.04&amp;lt;/math&amp;gt;. Получается, что &amp;lt;math&amp;gt;K_p &amp;lt; 125&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Для нахождения &amp;lt;math&amp;gt;K_v&amp;lt;/math&amp;gt; вместо &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; необходимо подставить наибольшее возможное для нее значение &amp;lt;math&amp;gt;\tfrac{K_v^2}{4 \cdot K_p}&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;K_p &amp;lt; \frac{2}{\frac{K_v^2}{4 \cdot K_p} \cdot T^2}, \quad K_p &amp;lt; \frac{2 \cdot 4 \cdot K_p}{K_v^2 \cdot T^2}, \quad 1 &amp;lt; \frac{8}{K_v^2 \cdot T^2}, \quad K_v^2 &amp;lt; \frac{8}{T^2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Окончательно,&lt;br /&gt;
:&amp;lt;math&amp;gt;K_v &amp;lt; \frac{2\sqrt{2}}{T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
При подстановке значения &amp;lt;math&amp;gt;T = 0.04&amp;lt;/math&amp;gt;, получается, что &amp;lt;math&amp;gt;K_v &amp;lt; 70&amp;lt;/math&amp;gt;. В реальных условиях эти пределы взяты еще меньше, для защиты от граничных случаев. Конкретно, &amp;lt;math&amp;gt;K_p&amp;lt;/math&amp;gt; по-умолчанию не может превышать 50, а &amp;lt;math&amp;gt;K_v&amp;lt;/math&amp;gt; — 30&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
[20:40:39] &amp;lt;droot@deeptown.org&amp;gt; так&lt;br /&gt;
[20:40:44] &amp;lt;droot@deeptown.org&amp;gt; а теперь - самое веселое&lt;br /&gt;
[20:40:51] &amp;lt;droot@deeptown.org&amp;gt; все то же самое, но только для вращения =)&lt;br /&gt;
[20:46:32] &amp;lt;korvin&amp;gt; мде..&lt;br /&gt;
[20:46:56] &amp;lt;droot@deeptown.org&amp;gt; там почти то же самое&lt;br /&gt;
[20:47:00] &amp;lt;korvin&amp;gt; ну вообще там не должно быть сильно сложно&lt;br /&gt;
[20:47:02] &amp;lt;korvin&amp;gt; то же самое по сути&lt;br /&gt;
[20:47:09] &amp;lt;droot@deeptown.org&amp;gt; т.е. плоская задача там будет точно такой же&lt;br /&gt;
[20:47:24] &amp;lt;droot@deeptown.org&amp;gt; только не y(t), а fi(t) - угол от времени&lt;br /&gt;
[20:48:03] &amp;lt;droot@deeptown.org&amp;gt; я вот не могу сообразить, что будет являться трехмерным представлением этого угла&lt;br /&gt;
[20:48:37] &amp;lt;korvin&amp;gt; в смысле?&lt;br /&gt;
[20:49:14] &amp;lt;droot@deeptown.org&amp;gt; ну вот в случае движения, от нашей задачи можно легко перейти к трехмерной, просто взяв не y(t), а r(t) - вектор координаты&lt;br /&gt;
[20:49:18] &amp;lt;droot@deeptown.org&amp;gt; мм..&lt;br /&gt;
[20:49:23] &amp;lt;droot@deeptown.org&amp;gt; ну точнее не совсем так&lt;br /&gt;
[20:49:27] &amp;lt;droot@deeptown.org&amp;gt; там же надо разность брать&lt;br /&gt;
[20:49:32] &amp;lt;droot@deeptown.org&amp;gt; а, ну да&lt;br /&gt;
[20:49:44] &amp;lt;droot@deeptown.org&amp;gt; т.е. вместо y(t) мы пишем разность векторов между сервером и клиентом&lt;br /&gt;
[20:49:45] &amp;lt;korvin&amp;gt; ну там вроде же просто 3 угла, которые можно точно так же линейно интерполировать&lt;br /&gt;
[20:50:45] &amp;lt;droot@deeptown.org&amp;gt; Vx - это модуль серверной скорости&lt;br /&gt;
[20:50:58] &amp;lt;droot@deeptown.org&amp;gt; ну а все остальное понятно&lt;br /&gt;
[20:51:29] &amp;lt;droot@deeptown.org&amp;gt; что же касается углов&lt;br /&gt;
[20:51:41] &amp;lt;droot@deeptown.org&amp;gt; ну если посмотреть на задачу с практической точки зрения&lt;br /&gt;
[20:51:50] &amp;lt;droot@deeptown.org&amp;gt; т.е. у нас есть два кватерниона&lt;br /&gt;
[20:53:24] &amp;lt;droot@deeptown.org&amp;gt; надо сообразить, что будет являться кватернионом вращения из одного положения во второе&lt;br /&gt;
[20:53:50] &amp;lt;korvin&amp;gt; в смысле что будет?&lt;br /&gt;
[20:54:12] &amp;lt;korvin&amp;gt; м... может проще представить кватернион в виде косинусов и дальше по частям?&lt;br /&gt;
[20:54:21] &amp;lt;korvin&amp;gt; покомпонентно в смысле&lt;br /&gt;
[20:54:23] &amp;lt;droot@deeptown.org&amp;gt; это долго считать&lt;br /&gt;
[20:59:55] &amp;lt;droot@deeptown.org&amp;gt; мм ну вообще все понятно&lt;br /&gt;
[21:00:19] &amp;lt;droot@deeptown.org&amp;gt; если сумма вращений задается кватернионом Q = q2 * q1&lt;br /&gt;
[21:00:47] &amp;lt;droot@deeptown.org&amp;gt; то разность вращений будет q2 = Q * q1^(-1) = Q * q1'&lt;br /&gt;
[21:01:36] &amp;lt;droot@deeptown.org&amp;gt; т.е. мы легко можем посчитать кватернион, который является разностью между клиентским и серверным вращениями&lt;br /&gt;
[21:03:54] &amp;lt;droot@deeptown.org&amp;gt; для того, чтобы повернуть тело этим кватернионом, нам нужно приложить к нему момент вращения, направление которого также можно посчитать&lt;br /&gt;
[21:05:56] &amp;lt;droot@deeptown.org&amp;gt; а зависеть он будет от тех же модуля серверной угловой скорости, собсно кватерниона разности, момента вращения, ну и соответственно некоторого коэффициента&lt;br /&gt;
[21:08:54] &amp;lt;droot@deeptown.org&amp;gt; ну а для стабилизации разности угловых скоростей все элементарно: момент вращения будет просто пропорционален разности векторов угловых скоростей (ну и направлен вдоль вектора этой разности)&lt;br /&gt;
[21:11:22] &amp;lt;korvin&amp;gt; так, ну это понятно&lt;br /&gt;
[21:11:32] &amp;lt;korvin&amp;gt; а с перерегулированием что делать?&lt;br /&gt;
[21:11:37] &amp;lt;korvin&amp;gt; ну то есть если перестараемся&lt;br /&gt;
[21:11:41] &amp;lt;droot@deeptown.org&amp;gt; (я вот щас мысленно пытаюсь себе это представить и думаю нсчет вектора разности...)&lt;br /&gt;
[21:12:44] &amp;lt;droot@deeptown.org&amp;gt; там собсно соотношение этих коэффициентов точно такое же должно получиться&lt;br /&gt;
[21:13:34] &amp;lt;droot@deeptown.org&amp;gt; т.е. W &amp;lt; Kw^2 / (4*Kr)&lt;br /&gt;
[21:42:36] &amp;lt;droot@deeptown.org&amp;gt; хочешь почитать веселую книжку? =)&lt;br /&gt;
[21:43:09] &amp;lt;droot@deeptown.org&amp;gt; я тут с аленкой попробовал проконсультироваться, и она мне оч посоветовала =) ландау-лифшиц &amp;quot;механика&amp;quot; называется =)&lt;br /&gt;
[21:55:38] &amp;lt;droot@deeptown.org&amp;gt; вообще, вот что до ограничений сверху для этих всех коэффициентов - я думаю, что надо просто взять некую константу - скажем, 30 - и ей ограничиться&lt;br /&gt;
[21:55:53] &amp;lt;droot@deeptown.org&amp;gt; т.е. Kv &amp;lt; 30&lt;br /&gt;
[21:56:10] &amp;lt;droot@deeptown.org&amp;gt; ну, для Kp можно ограничение чуть больше - скажем, Kp &amp;lt; 50&lt;br /&gt;
[21:58:57] &amp;lt;droot@deeptown.org&amp;gt; мм. а вообще, я бы даже не так сделал&lt;br /&gt;
[21:59:22] &amp;lt;droot@deeptown.org&amp;gt; мне кажется что параметризовать надо не через Kp и Kv, а через Vx и Kp, а уже Kv выражать через них&lt;br /&gt;
[21:59:36] &amp;lt;korvin&amp;gt; мм&lt;br /&gt;
[21:59:39] &amp;lt;korvin&amp;gt; а смысл?&lt;br /&gt;
[21:59:41] &amp;lt;droot@deeptown.org&amp;gt; (ну т.е. Vx - это максимальная скорость)&lt;br /&gt;
[21:59:50] &amp;lt;droot@deeptown.org&amp;gt; а это более понятные пользователю числа&lt;br /&gt;
[22:01:30] &amp;lt;droot@deeptown.org&amp;gt; хотя... ладно, фиг с ним, пусть будет напрямую&lt;br /&gt;
[22:01:40] &amp;lt;droot@deeptown.org&amp;gt; надо еще подумать, какие значения по-умолчанию лучше всего взять&lt;br /&gt;
[22:01:59] &amp;lt;droot@deeptown.org&amp;gt; ну Vx видимо надо брать где-то 10 как раз - это 36 км/ч&lt;br /&gt;
[22:02:22] &amp;lt;korvin&amp;gt; 10 м/с не жирно ли?&lt;br /&gt;
[22:02:24] &amp;lt;droot@deeptown.org&amp;gt; при большей уже вряд ли будут заметны эти силы&lt;br /&gt;
[22:02:55] &amp;lt;droot@deeptown.org&amp;gt; ну 36 км/ч - это где-то как раз граница воспринимаемых скоростей имхо&lt;br /&gt;
[22:04:02] &amp;lt;droot@deeptown.org&amp;gt; Kv предлагаю взять равным где-то 20&lt;br /&gt;
[22:04:46] &amp;lt;droot@deeptown.org&amp;gt; при этом будет хороший запас до сваливания из-за шага рассчета, но и время стабилизации будет достаточно малым&lt;br /&gt;
[22:04:55] &amp;lt;droot@deeptown.org&amp;gt; ну а Kp щас посчитаем&lt;br /&gt;
[22:05:11] &amp;lt;droot@deeptown.org&amp;gt; Vx = Kv^2 / (4*Kp)&lt;br /&gt;
[22:05:26] &amp;lt;droot@deeptown.org&amp;gt; Kp = Vx * 4 / Kv^2&lt;br /&gt;
[22:05:37] &amp;lt;droot@deeptown.org&amp;gt; тьфу&lt;br /&gt;
[22:05:57] &amp;lt;droot@deeptown.org&amp;gt; Kp = Kv&amp;amp;2 / (Vx*4)&lt;br /&gt;
[22:06:31] &amp;lt;droot@deeptown.org&amp;gt; Kp = 20^2 / 40 = 10&lt;br /&gt;
[22:06:40] &amp;lt;droot@deeptown.org&amp;gt; ну, вполне себе круглые числа =)&lt;br /&gt;
[22:06:48] &amp;lt;droot@deeptown.org&amp;gt; Vx = 10, Kp = 10, Kv = 20&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%81%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8</id>
		<title>Алгоритм синхронизации</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%81%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8"/>
				<updated>2008-10-24T13:43:36Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* Оценка параметров */&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;
:&amp;lt;math&amp;gt;s(t_i) = f(t_i), \quad s'(t_i) = f'(t_i)\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Уравнения сплайна:&lt;br /&gt;
:&amp;lt;math&amp;gt;s(t) = a + bt + ct^2 + dt^3\!&amp;lt;/math&amp;gt;&lt;br /&gt;
:&amp;lt;math&amp;gt;s'(t) = b + 2ct + 3dt^2\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Для нахождения коэффициентов &amp;lt;math&amp;gt;a, b, c, d&amp;lt;/math&amp;gt; записываем систему уравнений:&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
a + bt_0 + ct_0^2 + dt_0^3 = f(t_0) \\&lt;br /&gt;
a + bt_1 + ct_1^2 + dt_1^3 = f(t_1) \\&lt;br /&gt;
b + 2ct_0 + 3dt_0^2 = f'(t_0) \\&lt;br /&gt;
b + 2ct_1 + 3dt_1^2 = f'(t_1)&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Подставляем известные значения в правой части системы (даны по условию):&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
a + bt_0 + ct_0^2 + dt_0^3 = x_0 \\&lt;br /&gt;
a + bt_1 + ct_1^2 + dt_1^3 = x_1 \\&lt;br /&gt;
b + 2ct_0 + 3dt_0^2 = v_0 \\&lt;br /&gt;
b + 2ct_1 + 3dt_1^2 = v_1&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Поскольку сплайн не зависит от конкретных значений &amp;lt;math&amp;gt;t_0&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;t_1&amp;lt;/math&amp;gt;, положим &amp;lt;math&amp;gt;t_0 = 0&amp;lt;/math&amp;gt;, а &amp;lt;math&amp;gt;t_1 = t&amp;lt;/math&amp;gt;. В результате, пара уравнений становится тривиальной:&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
a = x_0 \\&lt;br /&gt;
a + bt_1 + ct_1^2 + dt_1^3 = x_1 \\&lt;br /&gt;
b = v_0 \\&lt;br /&gt;
b + 2ct_1 + 3dt_1^2 = v_1&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Заменяем в оставшихся уравнениях известные теперь коэффициенты и получаем конечную систему:&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
x_0 + v_0t_1 + ct_1^2 + dt_1^3 = x_1 \\&lt;br /&gt;
v_0 + 2ct_1 + 3dt_1^2 = v_1&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
После нехитрых манипуляций, получаем выражения для оставшихся коэффициентов:&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
c = \frac{3x_1 - 3x_0 - 2v_0t - v_1t}{t^2} \\&lt;br /&gt;
d = \frac{v_1t - 2x_1 + 2x_0 + v_ot}{t^3}&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ниже представлены графики оригинальной функции с наложенным на них графиком сплайна, построенного по точкам. Парабола и экспонента построены по фиксированному набору точек (-2.5, -2, -0.5, 0.5, 2, 2.5). Синусоида построена по точкам с интервалом 0.05.&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
Изображение:Exp.gif|Экспонента&lt;br /&gt;
Изображение:Parabola2.gif|Парабола&lt;br /&gt;
Изображение:Sin.gif|Синус&lt;br /&gt;
&amp;lt;/gallery&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;
Коррекция осуществляется путем приложения сторонней силы к движущемуся телу так, чтобы &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;
Осталось убедиться, что сумма этих сил действительно стабилизирует траекторию движения объекта, не приведет к колебаниям, и найти оптимальные значения для коэффициентов двух сил.&lt;br /&gt;
&lt;br /&gt;
Чтобы упростить себе жизнь, рассмотрим двумерный случай. Пусть серверная траектория тела совпадает с осью X; клиентская траектория — параллельна этой оси и находится от нее на расстоянии, равном H. В нулевой момент времени тело находится в нуле по оси X как на клиентской, так и на серверной траекториях.&lt;br /&gt;
&lt;br /&gt;
Пусть и серверная, и клиентская точки имеют горизонтальную скорость &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt;, а по вертикальной оси они неподвижны. Никаких прочих сил на объект не действует. Поскольку никаких сил по горизонтали не действует, мы будем рассматривать только движение по оси y.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Сила коррекции высоты, по такой модели, будет направлена &amp;quot;вниз&amp;quot; на эту точку, и будет равна: &lt;br /&gt;
:&amp;lt;math&amp;gt;F_p = - K_p \cdot y(t) \cdot V_x \cdot m&amp;lt;/math&amp;gt;&lt;br /&gt;
где &amp;lt;math&amp;gt;y&amp;lt;/math&amp;gt; — это высота точки и &lt;br /&gt;
:&amp;lt;math&amp;gt;y(0) = H\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Множитель &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; мы добавляем специально, чтобы уменьшить влияние силы коррекции на малых скоростях (иначе еле движущееся тело будет менять свое положение заметными глазу рывками).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Сила коррекции вертикальной скорости точки:&lt;br /&gt;
:&amp;lt;math&amp;gt;F_v = - K_v \cdot V_y(t) \cdot m&amp;lt;/math&amp;gt;&lt;br /&gt;
и &lt;br /&gt;
:&amp;lt;math&amp;gt;V_y(0) = 0\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Известно, что скорость — это производная координаты по времени:&lt;br /&gt;
:&amp;lt;math&amp;gt;V_y(t) = \frac{\partial y(t)}{\partial t}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Соответственно, сила, которая действует на объект:&lt;br /&gt;
:&amp;lt;math&amp;gt;F(t) = m \cdot y''(t) = F_p + F_v = - K_p \cdot y(t) \cdot V_x \cdot m - K_v \cdot V_y(t) \cdot m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;F - F_p - F_v = 0\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Разделив на массу, и записав уравнение в дифференциальной форме, получим:&lt;br /&gt;
:&amp;lt;math&amp;gt;y''(t) + K_v \cdot y'(t) + K_p \cdot y(t) \cdot Vx = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Перепишем параметрически:&lt;br /&gt;
:&amp;lt;math&amp;gt;y''(t) + A \cdot y'(t) + B \cdot y(t) = 0\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Характеристическое уравнение:&lt;br /&gt;
:&amp;lt;math&amp;gt;\lambda^2 + A \cdot \lambda + B = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Дискриминант характеристического уравнения:&lt;br /&gt;
:&amp;lt;math&amp;gt;D = A^2 - 4 \cdot B = K_v^2 - 4 \cdot K_p \cdot V_x&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для исключения колебательного процесса, необходимо условие &amp;lt;math&amp;gt;D \geqslant 0&amp;lt;/math&amp;gt;. Следовательно:&lt;br /&gt;
:&amp;lt;math&amp;gt;K_v^2 - 4 \cdot K_p \cdot V_x \geqslant 0&amp;lt;/math&amp;gt;&lt;br /&gt;
:&amp;lt;math&amp;gt;K_v^2 \geqslant 4 \cdot K_p \cdot V_x, \quad V_x \leqslant \frac{K_v^2}{4 \cdot K_p}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Видно, что если &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; будет больше чем эта дробь, то возникнут колебания (нарушается условие &amp;lt;math&amp;gt;D \geqslant 0&amp;lt;/math&amp;gt;). Поэтому, при малых скоростях используется само значение &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt;, а когда &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; численно становится больше этой дроби, следует заменять ее на эту дробь (ограничение сверху).&lt;br /&gt;
&lt;br /&gt;
В конечном счете, коэффициенты &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; выражаются как&lt;br /&gt;
:&amp;lt;math&amp;gt;\alpha_{1,2} = \frac{-K_v \pm \sqrt{D}}{2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Далее, найдем &amp;lt;math&amp;gt;C_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;C_2&amp;lt;/math&amp;gt;: &lt;br /&gt;
:&amp;lt;math&amp;gt;y(t) = C_1 \cdot e^{\alpha_1 t} + C_2 \cdot e^{\alpha_2 t}&amp;lt;/math&amp;gt;&lt;br /&gt;
Зная начальные условия  &amp;lt;math&amp;gt;y(0) = H&amp;lt;/math&amp;gt; (начальное расстояние между объектами) и &amp;lt;math&amp;gt;y'(t) = 0&amp;lt;/math&amp;gt; получаем уравнение:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_1 \cdot e^{\alpha_1 \cdot 0} + C_2 \cdot e^{\alpha_2 \cdot 0} = y(0) = H&amp;lt;/math&amp;gt; &lt;br /&gt;
следовательно &lt;br /&gt;
:&amp;lt;math&amp;gt;C_1 + C_2 = H\!&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из второго условия:&lt;br /&gt;
:&amp;lt;math&amp;gt;\alpha_1 \cdot C_1 \cdot e^{\alpha_1 \cdot 0} + \alpha_2 \cdot C_2 \cdot e^{\alpha_2 \cdot 0} = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
:&amp;lt;math&amp;gt;\alpha_1 \cdot C_1 + \alpha_2 \cdot C_2 = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Получаем систему следующих уравнений:&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
C_1 + C_2 = H \\&lt;br /&gt;
\alpha_1 \cdot C_1 + \alpha_2 \cdot C_2 = 0&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Решая систему относительно &amp;lt;math&amp;gt;C_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;C_2&amp;lt;/math&amp;gt;, получаем&lt;br /&gt;
:&amp;lt;math&amp;gt;C_{1,2} = \left ( \frac{1}{2} \pm \frac{K_v}{\sqrt{D}} \right ) \cdot H&amp;lt;/math&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;quot;между&amp;quot; коррекциями тело предоставлено само себе, оно и будет двигаться в указанную ему сторону. В худшем случае, при больших и плохо подобранных параметрах, уже после первого корректирующего воздействия, тело вылетит &amp;quot;за траекторию&amp;quot;, соответственно возникнут колебания (возможно даже возрастающие).&lt;br /&gt;
&lt;br /&gt;
Для избежания этого неприятного момента, попробуем оценить параметры и найти их &amp;quot;практический потолок&amp;quot;, с тем, чтобы не позволять пользователю задавать значения выходящие за границы.&lt;br /&gt;
&lt;br /&gt;
Итак, при моделировании, будем считать что в течение шага тело движется по прямой. Соответственно, сила, которая будет действовать на тело в течение первого шага, т.е. времени &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, будет равна &lt;br /&gt;
:&amp;lt;math&amp;gt;F_p = - K_p \cdot V_x \cdot H \cdot m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Соответственно, в течение первого шага тело будет двигаться с ускорением &lt;br /&gt;
:&amp;lt;math&amp;gt;a = - K_p \cdot Vx \cdot H&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Условие стабилизации — расстояние, которое преодолеет тело за первый шаг должно быть меньше &amp;lt;math&amp;gt;H&amp;lt;/math&amp;gt;:&lt;br /&gt;
:&amp;lt;math&amp;gt;K_p \cdot V_x \cdot H \cdot \frac{T^2}{2} &amp;lt; H, \quad K_p \cdot V_x \cdot T^2 &amp;lt; 2, \quad K_p &amp;lt; \frac{2}{V_x \cdot {T^2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Левая часть будет минимальной в случае, когда &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; максимальна, т.е. равна &amp;lt;math&amp;gt;\tfrac{K_v^2}{4 \cdot K_p}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Это означает, что в том случае когда модуль скорости тела меньше чем указанное значение, то коррекция происходить гладко; когда больше — в формуле для силы стабилизации положения &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; заменяется на &amp;lt;math&amp;gt;\tfrac{K_v^2}{4 \cdot K_p}&amp;lt;/math&amp;gt;. Объяснение было дано выше, при оценке дискриминанта характеристического уравнения.&lt;br /&gt;
&lt;br /&gt;
Из этого следует, что чтобы действительно сделать невидимым действие нашей силы на малых скоростях, необходимо, чтобы значение &amp;lt;math&amp;gt;\tfrac{K_v^2}{4 \cdot K_p}&amp;lt;/math&amp;gt; было бы достаточно большим. Мы взяли его по-умолчанию равным 10, но это значение можно бдет менять в свойствах каждого конкретного объекта.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Осталось только численно оценить коэффициенты &amp;lt;math&amp;gt;K_p&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;K_v&amp;lt;/math&amp;gt;. Для &amp;lt;math&amp;gt;K_p&amp;lt;/math&amp;gt; конкретное значение получается, если подставить в условие &lt;br /&gt;
:&amp;lt;math&amp;gt;K_p &amp;lt; \frac{2}{V_x \cdot T^2}&amp;lt;/math&amp;gt;&lt;br /&gt;
значения &amp;lt;math&amp;gt;V_x = 10&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;T = 0.04&amp;lt;/math&amp;gt;. Получается, что &amp;lt;math&amp;gt;K_p &amp;lt; 125&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Для нахождения &amp;lt;math&amp;gt;K_v&amp;lt;/math&amp;gt; вместо &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; необходимо подставить наибольшее возможное для нее значение &amp;lt;math&amp;gt;\tfrac{K_v^2}{4 \cdot K_p}&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;K_p &amp;lt; \frac{2}{\frac{K_v^2}{4 \cdot K_p} \cdot T^2}, \quad K_p &amp;lt; \frac{2 \cdot 4 \cdot K_p}{K_v^2 \cdot T^2}, \quad 1 &amp;lt; \frac{8}{K_v^2 \cdot T^2}, \quad K_v^2 &amp;lt; \frac{8}{T^2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Окончательно,&lt;br /&gt;
:&amp;lt;math&amp;gt;K_v &amp;lt; \frac{2\sqrt{2}}{T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
При подстановке значения &amp;lt;math&amp;gt;T = 0.04&amp;lt;/math&amp;gt;, получается, что &amp;lt;math&amp;gt;K_v &amp;lt; 70&amp;lt;/math&amp;gt;. В реальных условиях эти пределы взяты еще меньше, для защиты от граничных случаев. Конкретно, &amp;lt;math&amp;gt;K_p&amp;lt;/math&amp;gt; по-умолчанию не может превышать 50, а &amp;lt;math&amp;gt;K_v&amp;lt;/math&amp;gt; — 30&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
[20:40:39] &amp;lt;droot@deeptown.org&amp;gt; так&lt;br /&gt;
[20:40:44] &amp;lt;droot@deeptown.org&amp;gt; а теперь - самое веселое&lt;br /&gt;
[20:40:51] &amp;lt;droot@deeptown.org&amp;gt; все то же самое, но только для вращения =)&lt;br /&gt;
[20:46:32] &amp;lt;korvin&amp;gt; мде..&lt;br /&gt;
[20:46:56] &amp;lt;droot@deeptown.org&amp;gt; там почти то же самое&lt;br /&gt;
[20:47:00] &amp;lt;korvin&amp;gt; ну вообще там не должно быть сильно сложно&lt;br /&gt;
[20:47:02] &amp;lt;korvin&amp;gt; то же самое по сути&lt;br /&gt;
[20:47:09] &amp;lt;droot@deeptown.org&amp;gt; т.е. плоская задача там будет точно такой же&lt;br /&gt;
[20:47:24] &amp;lt;droot@deeptown.org&amp;gt; только не y(t), а fi(t) - угол от времени&lt;br /&gt;
[20:48:03] &amp;lt;droot@deeptown.org&amp;gt; я вот не могу сообразить, что будет являться трехмерным представлением этого угла&lt;br /&gt;
[20:48:37] &amp;lt;korvin&amp;gt; в смысле?&lt;br /&gt;
[20:49:14] &amp;lt;droot@deeptown.org&amp;gt; ну вот в случае движения, от нашей задачи можно легко перейти к трехмерной, просто взяв не y(t), а r(t) - вектор координаты&lt;br /&gt;
[20:49:18] &amp;lt;droot@deeptown.org&amp;gt; мм..&lt;br /&gt;
[20:49:23] &amp;lt;droot@deeptown.org&amp;gt; ну точнее не совсем так&lt;br /&gt;
[20:49:27] &amp;lt;droot@deeptown.org&amp;gt; там же надо разность брать&lt;br /&gt;
[20:49:32] &amp;lt;droot@deeptown.org&amp;gt; а, ну да&lt;br /&gt;
[20:49:44] &amp;lt;droot@deeptown.org&amp;gt; т.е. вместо y(t) мы пишем разность векторов между сервером и клиентом&lt;br /&gt;
[20:49:45] &amp;lt;korvin&amp;gt; ну там вроде же просто 3 угла, которые можно точно так же линейно интерполировать&lt;br /&gt;
[20:50:45] &amp;lt;droot@deeptown.org&amp;gt; Vx - это модуль серверной скорости&lt;br /&gt;
[20:50:58] &amp;lt;droot@deeptown.org&amp;gt; ну а все остальное понятно&lt;br /&gt;
[20:51:29] &amp;lt;droot@deeptown.org&amp;gt; что же касается углов&lt;br /&gt;
[20:51:41] &amp;lt;droot@deeptown.org&amp;gt; ну если посмотреть на задачу с практической точки зрения&lt;br /&gt;
[20:51:50] &amp;lt;droot@deeptown.org&amp;gt; т.е. у нас есть два кватерниона&lt;br /&gt;
[20:53:24] &amp;lt;droot@deeptown.org&amp;gt; надо сообразить, что будет являться кватернионом вращения из одного положения во второе&lt;br /&gt;
[20:53:50] &amp;lt;korvin&amp;gt; в смысле что будет?&lt;br /&gt;
[20:54:12] &amp;lt;korvin&amp;gt; м... может проще представить кватернион в виде косинусов и дальше по частям?&lt;br /&gt;
[20:54:21] &amp;lt;korvin&amp;gt; покомпонентно в смысле&lt;br /&gt;
[20:54:23] &amp;lt;droot@deeptown.org&amp;gt; это долго считать&lt;br /&gt;
[20:59:55] &amp;lt;droot@deeptown.org&amp;gt; мм ну вообще все понятно&lt;br /&gt;
[21:00:19] &amp;lt;droot@deeptown.org&amp;gt; если сумма вращений задается кватернионом Q = q2 * q1&lt;br /&gt;
[21:00:47] &amp;lt;droot@deeptown.org&amp;gt; то разность вращений будет q2 = Q * q1^(-1) = Q * q1'&lt;br /&gt;
[21:01:36] &amp;lt;droot@deeptown.org&amp;gt; т.е. мы легко можем посчитать кватернион, который является разностью между клиентским и серверным вращениями&lt;br /&gt;
[21:03:54] &amp;lt;droot@deeptown.org&amp;gt; для того, чтобы повернуть тело этим кватернионом, нам нужно приложить к нему момент вращения, направление которого также можно посчитать&lt;br /&gt;
[21:05:56] &amp;lt;droot@deeptown.org&amp;gt; а зависеть он будет от тех же модуля серверной угловой скорости, собсно кватерниона разности, момента вращения, ну и соответственно некоторого коэффициента&lt;br /&gt;
[21:08:54] &amp;lt;droot@deeptown.org&amp;gt; ну а для стабилизации разности угловых скоростей все элементарно: момент вращения будет просто пропорционален разности векторов угловых скоростей (ну и направлен вдоль вектора этой разности)&lt;br /&gt;
[21:11:22] &amp;lt;korvin&amp;gt; так, ну это понятно&lt;br /&gt;
[21:11:32] &amp;lt;korvin&amp;gt; а с перерегулированием что делать?&lt;br /&gt;
[21:11:37] &amp;lt;korvin&amp;gt; ну то есть если перестараемся&lt;br /&gt;
[21:11:41] &amp;lt;droot@deeptown.org&amp;gt; (я вот щас мысленно пытаюсь себе это представить и думаю нсчет вектора разности...)&lt;br /&gt;
[21:12:44] &amp;lt;droot@deeptown.org&amp;gt; там собсно соотношение этих коэффициентов точно такое же должно получиться&lt;br /&gt;
[21:13:34] &amp;lt;droot@deeptown.org&amp;gt; т.е. W &amp;lt; Kw^2 / (4*Kr)&lt;br /&gt;
[21:42:36] &amp;lt;droot@deeptown.org&amp;gt; хочешь почитать веселую книжку? =)&lt;br /&gt;
[21:43:09] &amp;lt;droot@deeptown.org&amp;gt; я тут с аленкой попробовал проконсультироваться, и она мне оч посоветовала =) ландау-лифшиц &amp;quot;механика&amp;quot; называется =)&lt;br /&gt;
[21:55:38] &amp;lt;droot@deeptown.org&amp;gt; вообще, вот что до ограничений сверху для этих всех коэффициентов - я думаю, что надо просто взять некую константу - скажем, 30 - и ей ограничиться&lt;br /&gt;
[21:55:53] &amp;lt;droot@deeptown.org&amp;gt; т.е. Kv &amp;lt; 30&lt;br /&gt;
[21:56:10] &amp;lt;droot@deeptown.org&amp;gt; ну, для Kp можно ограничение чуть больше - скажем, Kp &amp;lt; 50&lt;br /&gt;
[21:58:57] &amp;lt;droot@deeptown.org&amp;gt; мм. а вообще, я бы даже не так сделал&lt;br /&gt;
[21:59:22] &amp;lt;droot@deeptown.org&amp;gt; мне кажется что параметризовать надо не через Kp и Kv, а через Vx и Kp, а уже Kv выражать через них&lt;br /&gt;
[21:59:36] &amp;lt;korvin&amp;gt; мм&lt;br /&gt;
[21:59:39] &amp;lt;korvin&amp;gt; а смысл?&lt;br /&gt;
[21:59:41] &amp;lt;droot@deeptown.org&amp;gt; (ну т.е. Vx - это максимальная скорость)&lt;br /&gt;
[21:59:50] &amp;lt;droot@deeptown.org&amp;gt; а это более понятные пользователю числа&lt;br /&gt;
[22:01:30] &amp;lt;droot@deeptown.org&amp;gt; хотя... ладно, фиг с ним, пусть будет напрямую&lt;br /&gt;
[22:01:40] &amp;lt;droot@deeptown.org&amp;gt; надо еще подумать, какие значения по-умолчанию лучше всего взять&lt;br /&gt;
[22:01:59] &amp;lt;droot@deeptown.org&amp;gt; ну Vx видимо надо брать где-то 10 как раз - это 36 км/ч&lt;br /&gt;
[22:02:22] &amp;lt;korvin&amp;gt; 10 м/с не жирно ли?&lt;br /&gt;
[22:02:24] &amp;lt;droot@deeptown.org&amp;gt; при большей уже вряд ли будут заметны эти силы&lt;br /&gt;
[22:02:55] &amp;lt;droot@deeptown.org&amp;gt; ну 36 км/ч - это где-то как раз граница воспринимаемых скоростей имхо&lt;br /&gt;
[22:04:02] &amp;lt;droot@deeptown.org&amp;gt; Kv предлагаю взять равным где-то 20&lt;br /&gt;
[22:04:46] &amp;lt;droot@deeptown.org&amp;gt; при этом будет хороший запас до сваливания из-за шага рассчета, но и время стабилизации будет достаточно малым&lt;br /&gt;
[22:04:55] &amp;lt;droot@deeptown.org&amp;gt; ну а Kp щас посчитаем&lt;br /&gt;
[22:05:11] &amp;lt;droot@deeptown.org&amp;gt; Vx = Kv^2 / (4*Kp)&lt;br /&gt;
[22:05:26] &amp;lt;droot@deeptown.org&amp;gt; Kp = Vx * 4 / Kv^2&lt;br /&gt;
[22:05:37] &amp;lt;droot@deeptown.org&amp;gt; тьфу&lt;br /&gt;
[22:05:57] &amp;lt;droot@deeptown.org&amp;gt; Kp = Kv&amp;amp;2 / (Vx*4)&lt;br /&gt;
[22:06:31] &amp;lt;droot@deeptown.org&amp;gt; Kp = 20^2 / 40 = 10&lt;br /&gt;
[22:06:40] &amp;lt;droot@deeptown.org&amp;gt; ну, вполне себе круглые числа =)&lt;br /&gt;
[22:06:48] &amp;lt;droot@deeptown.org&amp;gt; Vx = 10, Kp = 10, Kv = 20&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	<entry>
		<id>http://man.deeptown.org/index.php/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%81%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8</id>
		<title>Алгоритм синхронизации</title>
		<link rel="alternate" type="text/html" href="http://man.deeptown.org/index.php/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%81%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8"/>
				<updated>2008-10-23T12:23:03Z</updated>
		
		<summary type="html">&lt;p&gt;Korvin: /* Поиск уравнения коррекции */&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;
:&amp;lt;math&amp;gt;s(t_i) = f(t_i), \quad s'(t_i) = f'(t_i)\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Уравнения сплайна:&lt;br /&gt;
:&amp;lt;math&amp;gt;s(t) = a + bt + ct^2 + dt^3\!&amp;lt;/math&amp;gt;&lt;br /&gt;
:&amp;lt;math&amp;gt;s'(t) = b + 2ct + 3dt^2\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Для нахождения коэффициентов &amp;lt;math&amp;gt;a, b, c, d&amp;lt;/math&amp;gt; записываем систему уравнений:&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
a + bt_0 + ct_0^2 + dt_0^3 = f(t_0) \\&lt;br /&gt;
a + bt_1 + ct_1^2 + dt_1^3 = f(t_1) \\&lt;br /&gt;
b + 2ct_0 + 3dt_0^2 = f'(t_0) \\&lt;br /&gt;
b + 2ct_1 + 3dt_1^2 = f'(t_1)&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Подставляем известные значения в правой части системы (даны по условию):&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
a + bt_0 + ct_0^2 + dt_0^3 = x_0 \\&lt;br /&gt;
a + bt_1 + ct_1^2 + dt_1^3 = x_1 \\&lt;br /&gt;
b + 2ct_0 + 3dt_0^2 = v_0 \\&lt;br /&gt;
b + 2ct_1 + 3dt_1^2 = v_1&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Поскольку сплайн не зависит от конкретных значений &amp;lt;math&amp;gt;t_0&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;t_1&amp;lt;/math&amp;gt;, положим &amp;lt;math&amp;gt;t_0 = 0&amp;lt;/math&amp;gt;, а &amp;lt;math&amp;gt;t_1 = t&amp;lt;/math&amp;gt;. В результате, пара уравнений становится тривиальной:&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
a = x_0 \\&lt;br /&gt;
a + bt_1 + ct_1^2 + dt_1^3 = x_1 \\&lt;br /&gt;
b = v_0 \\&lt;br /&gt;
b + 2ct_1 + 3dt_1^2 = v_1&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Заменяем в оставшихся уравнениях известные теперь коэффициенты и получаем конечную систему:&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
x_0 + v_0t_1 + ct_1^2 + dt_1^3 = x_1 \\&lt;br /&gt;
v_0 + 2ct_1 + 3dt_1^2 = v_1&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
После нехитрых манипуляций, получаем выражения для оставшихся коэффициентов:&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
c = \frac{3x_1 - 3x_0 - 2v_0t - v_1t}{t^2} \\&lt;br /&gt;
d = \frac{v_1t - 2x_1 + 2x_0 + v_ot}{t^3}&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ниже представлены графики оригинальной функции с наложенным на них графиком сплайна, построенного по точкам. Парабола и экспонента построены по фиксированному набору точек (-2.5, -2, -0.5, 0.5, 2, 2.5). Синусоида построена по точкам с интервалом 0.05.&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
Изображение:Exp.gif|Экспонента&lt;br /&gt;
Изображение:Parabola2.gif|Парабола&lt;br /&gt;
Изображение:Sin.gif|Синус&lt;br /&gt;
&amp;lt;/gallery&amp;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;
Чтобы упростить себе жизнь, рассмотрим одномерный случай. Пусть серверная &amp;quot;траектория&amp;quot; тела находится в точке 0; клиентская &amp;quot;траектория&amp;quot; — в точке с координатой H. Графически, это выглядит как вертикальная линия, в нуле — серверная траектория, в точке на высоте H — клиентская. Горизонтальную и вертикальную компоненты скорости будем рассматривать отдельно. &lt;br /&gt;
&lt;br /&gt;
Пусть серверная точка имеет горизонтальную скорость &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt;. Клиентская, в самом начале — горизонтальную скорость &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; и вертикальную, равную нулю.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Сила коррекции высоты, по такой модели, будет направлена &amp;quot;вниз&amp;quot; на эту точку, и будет равна: &lt;br /&gt;
:&amp;lt;math&amp;gt;F_p = - K_p \cdot y(t) \cdot V_x \cdot m&amp;lt;/math&amp;gt;&lt;br /&gt;
где &amp;lt;math&amp;gt;y&amp;lt;/math&amp;gt; — это высота точки и &lt;br /&gt;
:&amp;lt;math&amp;gt;y(0) = H\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Множитель &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; мы добавляем специально, чтобы уменьшить влияние силы коррекции на малых скоростях (иначе еле движущееся тело будет менять свое положение заметными глазу рывками).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Сила коррекции вертикальной скорости точки:&lt;br /&gt;
:&amp;lt;math&amp;gt;F_v = - K_v \cdot V_y(t) \cdot m&amp;lt;/math&amp;gt;&lt;br /&gt;
и &lt;br /&gt;
:&amp;lt;math&amp;gt;V_y(0) = 0\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Известно, что скорость — это производная координаты по времени:&lt;br /&gt;
:&amp;lt;math&amp;gt;V_y(t) = \frac{\partial y(t)}{\partial t}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Соответственно, сила, которая действует на объект:&lt;br /&gt;
:&amp;lt;math&amp;gt;F(t) = m \cdot y''(t) = F_p + F_v = - K_p \cdot y(t) \cdot V_x \cdot m - K_v \cdot V_y(t) \cdot m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;F - F_p - F_v = 0\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Разделив на массу, и записав уравнение в дифференциальной форме, получим:&lt;br /&gt;
:&amp;lt;math&amp;gt;y''(t) + K_v \cdot y'(t) + K_p \cdot y(t) \cdot Vx = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Перепишем параметрически:&lt;br /&gt;
:&amp;lt;math&amp;gt;y''(t) + A \cdot y'(t) + B \cdot y(t) = 0\!&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Характеристическое уравнение:&lt;br /&gt;
:&amp;lt;math&amp;gt;\lambda^2 + A \cdot \lambda + B = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Дискриминант характеристического уравнения:&lt;br /&gt;
:&amp;lt;math&amp;gt;D = A^2 - 4 \cdot B = K_v^2 - 4 \cdot K_p \cdot V_x&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для исключения колебательного процесса, необходимо условие &amp;lt;math&amp;gt;D \geqslant 0&amp;lt;/math&amp;gt;. Следовательно:&lt;br /&gt;
:&amp;lt;math&amp;gt;K_v^2 - 4 \cdot K_p \cdot V_x \geqslant 0&amp;lt;/math&amp;gt;&lt;br /&gt;
:&amp;lt;math&amp;gt;K_v^2 \geqslant 4 \cdot K_p \cdot V_x, \quad V_x \leqslant \frac{K_v^2}{4 \cdot K_p}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Видно, что если &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; будет больше чем эта дробь, то возникнут колебания (нарушается условие &amp;lt;math&amp;gt;D \geqslant 0&amp;lt;/math&amp;gt;). Поэтому, при малых скоростях используется само значение &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt;, а когда &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; численно становится больше этой дроби, следует заменять ее на эту дробь (ограничение сверху).&lt;br /&gt;
&lt;br /&gt;
В конечном счете, коэффициенты &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; выражаются как&lt;br /&gt;
:&amp;lt;math&amp;gt;\alpha_{1,2} = \frac{-K_v \pm \sqrt{D}}{2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Далее, найдем &amp;lt;math&amp;gt;C_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;C_2&amp;lt;/math&amp;gt;: &lt;br /&gt;
:&amp;lt;math&amp;gt;y(t) = C_1 \cdot e^{\alpha_1 t} + C_2 \cdot e^{\alpha_2 t}&amp;lt;/math&amp;gt;&lt;br /&gt;
Зная начальные условия  &amp;lt;math&amp;gt;y(0) = H&amp;lt;/math&amp;gt; (начальное расстояние между объектами) и &amp;lt;math&amp;gt;y'(t) = 0&amp;lt;/math&amp;gt; получаем уравнение:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_1 \cdot e^{\alpha_1 \cdot 0} + C_2 \cdot e^{\alpha_2 \cdot 0} = y(0) = H&amp;lt;/math&amp;gt; &lt;br /&gt;
следовательно &lt;br /&gt;
:&amp;lt;math&amp;gt;C_1 + C_2 = H\!&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из второго условия:&lt;br /&gt;
:&amp;lt;math&amp;gt;\alpha_1 \cdot C_1 \cdot e^{\alpha_1 \cdot 0} + \alpha_2 \cdot C_2 \cdot e^{\alpha_2 \cdot 0} = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
:&amp;lt;math&amp;gt;\alpha_1 \cdot C_1 + \alpha_2 \cdot C_2 = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Получаем систему следующих уравнений:&lt;br /&gt;
:&amp;lt;math&amp;gt;\begin{cases}&lt;br /&gt;
C_1 + C_2 = H \\&lt;br /&gt;
\alpha_1 \cdot C_1 + \alpha_2 \cdot C_2 = 0&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Решая систему относительно &amp;lt;math&amp;gt;C_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;C_2&amp;lt;/math&amp;gt;, получаем&lt;br /&gt;
:&amp;lt;math&amp;gt;C_{1,2} = \left ( \frac{1}{2} \pm \frac{K_v}{\sqrt{D}} \right ) \cdot H&amp;lt;/math&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;quot;между&amp;quot; коррекциями тело предоставлено само себе, оно и будет двигаться в указанную ему сторону. В худшем случае, при больших и плохо подобранных параметрах, уже после первого корректирующего воздействия, тело вылетит &amp;quot;за траекторию&amp;quot;, соответственно возникнут колебания (возможно даже возрастающие).&lt;br /&gt;
&lt;br /&gt;
Для избежания этого неприятного момента, попробуем оценить параметры и найти их &amp;quot;практический потолок&amp;quot;, с тем, чтобы не позволять пользователю задавать значения выходящие за границы.&lt;br /&gt;
&lt;br /&gt;
Итак, при моделировании, будем считать что в течение шага тело движется по прямой. Соответственно, сила, которая будет действовать на тело в течение первого шага, т.е. времени &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, будет равна &lt;br /&gt;
:&amp;lt;math&amp;gt;F_p = - K_p \cdot V_x \cdot H \cdot m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Соответственно, в течение первого шага тело будет двигаться с ускорением &lt;br /&gt;
:&amp;lt;math&amp;gt;a = - K_p \cdot Vx \cdot H&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Условие стабилизации — расстояние, которое преодолеет тело за первый шаг должно быть меньше &amp;lt;math&amp;gt;H&amp;lt;/math&amp;gt;:&lt;br /&gt;
:&amp;lt;math&amp;gt;K_p \cdot V_x \cdot H \cdot \frac{T^2}{2} &amp;lt; H, \quad K_p \cdot V_x \cdot \frac{T^2}{2} &amp;lt; 2, \quad K_p &amp;lt; \frac{2}{V_x \cdot {T^2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Левая часть будет минимальной в случае, когда &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; максимальна, т.е. равна &amp;lt;math&amp;gt;\tfrac{K_v^2}{4 \cdot K_p}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Это означает, что в том случае когда модуль скорости тела меньше чем указанное значение, то коррекция происходить гладко; когда больше — в формуле для силы стабилизации положения &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; заменяется на &amp;lt;math&amp;gt;\tfrac{K_v^2}{4 \cdot K_p}&amp;lt;/math&amp;gt;. Объяснение было дано выше, при оценке дискриминанта характеристического уравнения.&lt;br /&gt;
&lt;br /&gt;
Из этого следует, что чтобы действительно сделать невидимым действие нашей силы на малых скоростях, необходимо, чтобы значение &amp;lt;math&amp;gt;\tfrac{K_v^2}{4 \cdot K_p}&amp;lt;/math&amp;gt; было бы достаточно большим. Мы взяли его по-умолчанию равным 10, но это значение можно бдет менять в свойствах каждого конкретного объекта.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Осталось только численно оценить коэффициенты &amp;lt;math&amp;gt;K_p&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;K_v&amp;lt;/math&amp;gt;. Для &amp;lt;math&amp;gt;K_p&amp;lt;/math&amp;gt; конкретное значение получается, если подставить в условие &lt;br /&gt;
:&amp;lt;math&amp;gt;K_p &amp;lt; \frac{2}{V_x \cdot T^2}&amp;lt;/math&amp;gt;&lt;br /&gt;
значения &amp;lt;math&amp;gt;V_x = 10&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;T = 0.04&amp;lt;/math&amp;gt;. Получается, что &amp;lt;math&amp;gt;K_p &amp;lt; 125&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Для нахождения &amp;lt;math&amp;gt;K_v&amp;lt;/math&amp;gt; вместо &amp;lt;math&amp;gt;V_x&amp;lt;/math&amp;gt; необходимо подставить наибольшее возможное для нее значение &amp;lt;math&amp;gt;\tfrac{K_v^2}{4 \cdot K_p}&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;K_p &amp;lt; \frac{2}{\frac{K_v^2}{4 \cdot K_p} \cdot T^2}, \quad K_p &amp;lt; \frac{2 \cdot 4 \cdot K_p}{K_v^2 \cdot T^2}, \quad 1 &amp;lt; \frac{8}{K_v^2 \cdot T^2}, \quad K_v^2 &amp;lt; \frac{8}{T^2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Окончательно,&lt;br /&gt;
:&amp;lt;math&amp;gt;K_v &amp;lt; \frac{2\sqrt{2}}{T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
При подстановке значения &amp;lt;math&amp;gt;T = 0.04&amp;lt;/math&amp;gt;, получается, что &amp;lt;math&amp;gt;K_v &amp;lt; 70&amp;lt;/math&amp;gt;. В реальных условиях эти пределы взяты еще меньше, для защиты от граничных случаев. Конкретно, &amp;lt;math&amp;gt;K_p&amp;lt;/math&amp;gt; по-умолчанию не может превышать 50, а &amp;lt;math&amp;gt;K_v&amp;lt;/math&amp;gt; — 30&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
[20:40:39] &amp;lt;droot@deeptown.org&amp;gt; так&lt;br /&gt;
[20:40:44] &amp;lt;droot@deeptown.org&amp;gt; а теперь - самое веселое&lt;br /&gt;
[20:40:51] &amp;lt;droot@deeptown.org&amp;gt; все то же самое, но только для вращения =)&lt;br /&gt;
[20:46:32] &amp;lt;korvin&amp;gt; мде..&lt;br /&gt;
[20:46:56] &amp;lt;droot@deeptown.org&amp;gt; там почти то же самое&lt;br /&gt;
[20:47:00] &amp;lt;korvin&amp;gt; ну вообще там не должно быть сильно сложно&lt;br /&gt;
[20:47:02] &amp;lt;korvin&amp;gt; то же самое по сути&lt;br /&gt;
[20:47:09] &amp;lt;droot@deeptown.org&amp;gt; т.е. плоская задача там будет точно такой же&lt;br /&gt;
[20:47:24] &amp;lt;droot@deeptown.org&amp;gt; только не y(t), а fi(t) - угол от времени&lt;br /&gt;
[20:48:03] &amp;lt;droot@deeptown.org&amp;gt; я вот не могу сообразить, что будет являться трехмерным представлением этого угла&lt;br /&gt;
[20:48:37] &amp;lt;korvin&amp;gt; в смысле?&lt;br /&gt;
[20:49:14] &amp;lt;droot@deeptown.org&amp;gt; ну вот в случае движения, от нашей задачи можно легко перейти к трехмерной, просто взяв не y(t), а r(t) - вектор координаты&lt;br /&gt;
[20:49:18] &amp;lt;droot@deeptown.org&amp;gt; мм..&lt;br /&gt;
[20:49:23] &amp;lt;droot@deeptown.org&amp;gt; ну точнее не совсем так&lt;br /&gt;
[20:49:27] &amp;lt;droot@deeptown.org&amp;gt; там же надо разность брать&lt;br /&gt;
[20:49:32] &amp;lt;droot@deeptown.org&amp;gt; а, ну да&lt;br /&gt;
[20:49:44] &amp;lt;droot@deeptown.org&amp;gt; т.е. вместо y(t) мы пишем разность векторов между сервером и клиентом&lt;br /&gt;
[20:49:45] &amp;lt;korvin&amp;gt; ну там вроде же просто 3 угла, которые можно точно так же линейно интерполировать&lt;br /&gt;
[20:50:45] &amp;lt;droot@deeptown.org&amp;gt; Vx - это модуль серверной скорости&lt;br /&gt;
[20:50:58] &amp;lt;droot@deeptown.org&amp;gt; ну а все остальное понятно&lt;br /&gt;
[20:51:29] &amp;lt;droot@deeptown.org&amp;gt; что же касается углов&lt;br /&gt;
[20:51:41] &amp;lt;droot@deeptown.org&amp;gt; ну если посмотреть на задачу с практической точки зрения&lt;br /&gt;
[20:51:50] &amp;lt;droot@deeptown.org&amp;gt; т.е. у нас есть два кватерниона&lt;br /&gt;
[20:53:24] &amp;lt;droot@deeptown.org&amp;gt; надо сообразить, что будет являться кватернионом вращения из одного положения во второе&lt;br /&gt;
[20:53:50] &amp;lt;korvin&amp;gt; в смысле что будет?&lt;br /&gt;
[20:54:12] &amp;lt;korvin&amp;gt; м... может проще представить кватернион в виде косинусов и дальше по частям?&lt;br /&gt;
[20:54:21] &amp;lt;korvin&amp;gt; покомпонентно в смысле&lt;br /&gt;
[20:54:23] &amp;lt;droot@deeptown.org&amp;gt; это долго считать&lt;br /&gt;
[20:59:55] &amp;lt;droot@deeptown.org&amp;gt; мм ну вообще все понятно&lt;br /&gt;
[21:00:19] &amp;lt;droot@deeptown.org&amp;gt; если сумма вращений задается кватернионом Q = q2 * q1&lt;br /&gt;
[21:00:47] &amp;lt;droot@deeptown.org&amp;gt; то разность вращений будет q2 = Q * q1^(-1) = Q * q1'&lt;br /&gt;
[21:01:36] &amp;lt;droot@deeptown.org&amp;gt; т.е. мы легко можем посчитать кватернион, который является разностью между клиентским и серверным вращениями&lt;br /&gt;
[21:03:54] &amp;lt;droot@deeptown.org&amp;gt; для того, чтобы повернуть тело этим кватернионом, нам нужно приложить к нему момент вращения, направление которого также можно посчитать&lt;br /&gt;
[21:05:56] &amp;lt;droot@deeptown.org&amp;gt; а зависеть он будет от тех же модуля серверной угловой скорости, собсно кватерниона разности, момента вращения, ну и соответственно некоторого коэффициента&lt;br /&gt;
[21:08:54] &amp;lt;droot@deeptown.org&amp;gt; ну а для стабилизации разности угловых скоростей все элементарно: момент вращения будет просто пропорционален разности векторов угловых скоростей (ну и направлен вдоль вектора этой разности)&lt;br /&gt;
[21:11:22] &amp;lt;korvin&amp;gt; так, ну это понятно&lt;br /&gt;
[21:11:32] &amp;lt;korvin&amp;gt; а с перерегулированием что делать?&lt;br /&gt;
[21:11:37] &amp;lt;korvin&amp;gt; ну то есть если перестараемся&lt;br /&gt;
[21:11:41] &amp;lt;droot@deeptown.org&amp;gt; (я вот щас мысленно пытаюсь себе это представить и думаю нсчет вектора разности...)&lt;br /&gt;
[21:12:44] &amp;lt;droot@deeptown.org&amp;gt; там собсно соотношение этих коэффициентов точно такое же должно получиться&lt;br /&gt;
[21:13:34] &amp;lt;droot@deeptown.org&amp;gt; т.е. W &amp;lt; Kw^2 / (4*Kr)&lt;br /&gt;
[21:42:36] &amp;lt;droot@deeptown.org&amp;gt; хочешь почитать веселую книжку? =)&lt;br /&gt;
[21:43:09] &amp;lt;droot@deeptown.org&amp;gt; я тут с аленкой попробовал проконсультироваться, и она мне оч посоветовала =) ландау-лифшиц &amp;quot;механика&amp;quot; называется =)&lt;br /&gt;
[21:55:38] &amp;lt;droot@deeptown.org&amp;gt; вообще, вот что до ограничений сверху для этих всех коэффициентов - я думаю, что надо просто взять некую константу - скажем, 30 - и ей ограничиться&lt;br /&gt;
[21:55:53] &amp;lt;droot@deeptown.org&amp;gt; т.е. Kv &amp;lt; 30&lt;br /&gt;
[21:56:10] &amp;lt;droot@deeptown.org&amp;gt; ну, для Kp можно ограничение чуть больше - скажем, Kp &amp;lt; 50&lt;br /&gt;
[21:58:57] &amp;lt;droot@deeptown.org&amp;gt; мм. а вообще, я бы даже не так сделал&lt;br /&gt;
[21:59:22] &amp;lt;droot@deeptown.org&amp;gt; мне кажется что параметризовать надо не через Kp и Kv, а через Vx и Kp, а уже Kv выражать через них&lt;br /&gt;
[21:59:36] &amp;lt;korvin&amp;gt; мм&lt;br /&gt;
[21:59:39] &amp;lt;korvin&amp;gt; а смысл?&lt;br /&gt;
[21:59:41] &amp;lt;droot@deeptown.org&amp;gt; (ну т.е. Vx - это максимальная скорость)&lt;br /&gt;
[21:59:50] &amp;lt;droot@deeptown.org&amp;gt; а это более понятные пользователю числа&lt;br /&gt;
[22:01:30] &amp;lt;droot@deeptown.org&amp;gt; хотя... ладно, фиг с ним, пусть будет напрямую&lt;br /&gt;
[22:01:40] &amp;lt;droot@deeptown.org&amp;gt; надо еще подумать, какие значения по-умолчанию лучше всего взять&lt;br /&gt;
[22:01:59] &amp;lt;droot@deeptown.org&amp;gt; ну Vx видимо надо брать где-то 10 как раз - это 36 км/ч&lt;br /&gt;
[22:02:22] &amp;lt;korvin&amp;gt; 10 м/с не жирно ли?&lt;br /&gt;
[22:02:24] &amp;lt;droot@deeptown.org&amp;gt; при большей уже вряд ли будут заметны эти силы&lt;br /&gt;
[22:02:55] &amp;lt;droot@deeptown.org&amp;gt; ну 36 км/ч - это где-то как раз граница воспринимаемых скоростей имхо&lt;br /&gt;
[22:04:02] &amp;lt;droot@deeptown.org&amp;gt; Kv предлагаю взять равным где-то 20&lt;br /&gt;
[22:04:46] &amp;lt;droot@deeptown.org&amp;gt; при этом будет хороший запас до сваливания из-за шага рассчета, но и время стабилизации будет достаточно малым&lt;br /&gt;
[22:04:55] &amp;lt;droot@deeptown.org&amp;gt; ну а Kp щас посчитаем&lt;br /&gt;
[22:05:11] &amp;lt;droot@deeptown.org&amp;gt; Vx = Kv^2 / (4*Kp)&lt;br /&gt;
[22:05:26] &amp;lt;droot@deeptown.org&amp;gt; Kp = Vx * 4 / Kv^2&lt;br /&gt;
[22:05:37] &amp;lt;droot@deeptown.org&amp;gt; тьфу&lt;br /&gt;
[22:05:57] &amp;lt;droot@deeptown.org&amp;gt; Kp = Kv&amp;amp;2 / (Vx*4)&lt;br /&gt;
[22:06:31] &amp;lt;droot@deeptown.org&amp;gt; Kp = 20^2 / 40 = 10&lt;br /&gt;
[22:06:40] &amp;lt;droot@deeptown.org&amp;gt; ну, вполне себе круглые числа =)&lt;br /&gt;
[22:06:48] &amp;lt;droot@deeptown.org&amp;gt; Vx = 10, Kp = 10, Kv = 20&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>Korvin</name></author>	</entry>

	</feed>