Выражения — различия между версиями

Материал из Deeptown Manual
Перейти к: навигация, поиск
м (Операторы)
(Операторы)
Строка 76: Строка 76:
 
;9-15: В этой функции приводится пример применения вышеописанного класса. Сначала мы создаем инстанцию класса <tt>MyClass</tt> с помощью оператора <tt>'''new'''</tt>. Затем вызывается функция <tt>puts()</tt>, которая печатает значение свойства объекта. В третьей строке мы присваиваем свойству <tt>field</tt> (а значит и полю ''m_Field'') новое значение. Последние две строки показывают пример вызова метода с явным аргументом и с аргументом по умолчанию.
 
;9-15: В этой функции приводится пример применения вышеописанного класса. Сначала мы создаем инстанцию класса <tt>MyClass</tt> с помощью оператора <tt>'''new'''</tt>. Затем вызывается функция <tt>puts()</tt>, которая печатает значение свойства объекта. В третьей строке мы присваиваем свойству <tt>field</tt> (а значит и полю ''m_Field'') новое значение. Последние две строки показывают пример вызова метода с явным аргументом и с аргументом по умолчанию.
  
== Операторы ==
+
Good points all aorund. Truly appreciated.
 
+
С точки зрения языка К++, ''оператор'' — это специальная функция, имеющая строго определенное название, принимающая определенный набор параметров и возвращающая определенное значение. Фактически, операторы являются частью самого языка и обрабатываются отдельно от обычных функций еще на этапе синтаксического разбора программы, а следовательно, могут иметь любое имя (то есть, на них не распространяются правила именования [[Идентификатор|идентификаторов]]). Так и происходит. К примеру, все арифметические выражения что мы писали ранее, содержат наборы числовых констант, переменных и операторов, реализующих арифметические операции. То есть, <tt>+</tt>, <tt>-</tt>, <tt>*</tt>, <tt>/</tt>, <tt>++</tt> и многие другие — это операторы. Например, оператор <tt>+</tt>, объявленный в реализации [[Стандартная библиотека Gide|стандартной библиотеки]] для класса <tt>[[Стандартные типы данных#Целые числа|int]]</tt>, принимает в качестве параметра объект того же типа (<tt>int</tt>) и выполняет операцию сложения.
+
 
+
Существует большое количество разнообразных операторов, которые разделяются на два больших класса: ''унарные'' и ''бинарные'' операторы. Первые работают с единственным объектом (то есть, применяются для него же самого), вторые — оперируют двумя объектами. Таким образом, оператор <tt>+</tt> является бинарным оператором, в то время как <tt>++</tt> является унарным. В языках программирования, операторы применяются для самых различных задач, а не только для арифметики. Например, в книге уже был рассмотрен оператор <tt>'''as'''</tt>, служащий для явного [[Приведение типов|приведения типов]].
+
 
+
Однако, то что операторы являются частью языка программирования, не означает что программист не может их использовать для собственных нужд в своих классах. Операторы, подобно обычным функциям и методам, позволяют производить ''перегрузку'' и переобъявление. Приведем простой пример, иллюстрирующий этот механизм:
+
 
+
<source lang="kpp" line="1">
+
extend MyClass {
+
public:
+
    operator MyClass += (const MyClass mc) { m_Field += mc.field; return this; }
+
    operator MyClass += (const string s) { m_Field += s; return this; }
+
    const operator string () { return m_Field; }
+
}
+
 
+
function f() {
+
    var x = new MyClass;
+
    var y = new MyClass;
+
    x.field = "X";
+
    y.field = "Y";
+
    puts(x += y);
+
    puts(x += "Z");
+
}
+
</source>
+
 
+
 
+
;1-6: Используя [[Классы и объекты#Расширения|механизм расширений]], мы дополнили функциональность ранее описанного класса <tt>MyClass</tt>, добавив в него три оператора: две реализации бинарного оператора <tt>+=</tt> и оператор приведения типа. В блоке описания параметров для бинарных операторов мы указываем, с объектами какого типа должна работать данная конкретная реализация оператора. В первом случае, принимается объект нашего же класса <tt>MyClass</tt>, во втором случае — объект стандартного класса <tt>[[Стандартные типы данных#Строки|string]]</tt>. Оба оператора делают одно и то же: добавляют к текущему значению поля ''m_Field'', значение содержащееся в аргументе, то есть, в другом объекте, расположенном справа от оператора. Обратите внимание на тела операторов: для ''конкатенации'' строк применяется тот же самый оператор +=, однако следует понимать, что это уже применяется реализация оператора, объявленная в классе строки.
+
 
+
: Оператор приведения типов служит для преобразования объекта нашего класса <tt>MyClass</tt> к классу строки. Это может быть необходимо, например, для удобного вывода информации об обекте. При этом, инстанция класса указывается в выражении так, как будто она является строкой. Соответственно, ее можно будет передавать в качестве параметра функциям, принимающим строки — сперва будет выполнена операция приведения типа (с помощью нашего оператора), а затем результат будет передан как параметр. Стоит отметить, что эта операция выполняется компилятором автоматически. От нас требуется только реализовать сам оператор приведения типа.
+
 
+
;8-12: Для иллюстрирования вышесказанного, мы создаем два экземпляра нашего класса и присваиваем  свойству <tt>field</tt> новые значения: "X" и "Y" соответственно.
+
 
+
;13: Эта строка показывает наш оператор в действии. Как видите, мы выполняем операцию += для двух инстанций нашего класса. При этом, компилятор языка проверит, поддерживает ли наш класс такой оператор для аргумента типа <tt>MyClass</tt>. В нашем случае это так. Следовательно, при вычислении выражения он будет задействован. Результат выполнения операции <tt>x += y</tt> так же является объектом класса <tt>MyClass</tt> (на самом деле, это будет все та же инстанция ''x'', поскольку в реализации оператора применена конструкция "<tt>'''return this''';</tt>"). Но функция <tt>puts()</tt> принимает в качестве параметра строку, значит необходимо выполнить операцию приведения типов. Компилятор языка К++ вторично обратится за помощью к самому классу и проверит наличие оператора приведения к типу <tt>string</tt>. К счастью, такой оператор тоже имеется, поэтому компилятор заключает что типы ''приводимы'', и генерирует вызов оператора приведения. В заключение, результат выполнения оператора приведения (в нашем случае это будет строка "XY") будет передан функции <tt>puts()</tt>, которая уже распечатает его.
+
 
+
;14: Смысл этой конструкции мало чем отличается от предыдущей, за исключением того, что вторым ''операндом'' указан не объект класса <tt>MyClass</tt>, а строка. Соответственно, при компиляции будет задействована вторая реализация оператора <tt>+=</tt>; в остальном все просиходит точно так же.
+
 
+
 
+
'''Примечание:''' Здесь мы затронули лишь самые общие сведения об операторах и их применении. На самом деле, это очень обширная тема, требующая отдельного рассмотрения. Более подробно, про операторы можно почитать в [[K++#Операторы|специальном разделе]], целиком посвященном вопросам операторов.
+

Версия 16:50, 3 ноября 2011

Как уже было упомянуто в предыдущих главах (в истории ООП), одним из наиболее значимых нововведений языков программрования высокого уровня, стала возможность записи арифметических выражений в естественной для человека форме, с использованием операторов и функций. Для того чтобы посчитать значение выражения, теперь программисту требуется лишь правильно записать его, не заботясь о том, как оно будет вычисляться. Всю работу по разбору такого выражения, определению очередности выполнения операций берет на себя компилятор языка.

В этой главе мы узнаем, что такое выражения с точки зрения языка К++, как они формируются и на что нужно обращать внимание при их записи. Кратко будет затронута тема операторов, будут даны основные сведения о них. Более подробно, операторы как элемент языка К++, будут рассмотрены в конце книги, в отдельном разделе.

Арифметические операции

Наиболее простой и понятный тип выражений — это самые обычные арифметические выражения:

<source lang="kpp"> var x = 2 + 3 * 4; var y = (2 + 3) * 4; </source>

Для простоты мы используем хорошо нам известную конструкцию объявления переменной, но на этот раз в инициализаторе мы указываем не одну константу, вроде строки "hello world", а целое выражение. Выражением считается все, что записано между знаком "=" и точкой с запятой ";", которая завершает конструкцию.

При вычислении значения выражения применяются те же самые правила что и в обычной математике, то есть операции имеют приоритет и выполняются строго в порядке убывания приоритета. В первом случае, сначала будет вычислено подвыражение 3 * 4, к значению которого будет добавлено число 2; сумма будет установлена как значение переменной. Во втором случае, приоритет операций был изменен введением круглых скобок, которые имеют тот же смысл, что и в математике: сначала вычисляется значение в скобках, а затем остальные операции, опять же в порядке их приоритета. Скобок в выражение может быть сколько угодно, допускается вложенность.

...Таким образом, переменной x будет присвоено значение 14, а переменная y будет равна 20.

В выражениях могут указываться не только числовые константы. Так же как и в математике, в выражениях можно использовать переменные.

При вычислении выражения вмсето имени переменной подставляется ее значение. Таким образом, если в ходе рассчетов выражения, переменная изменит свое значение, то вместе следующего вхождения переменной может быть подставлено уже новое значение. А чтобы с уверенностью сказать "может быть подставлено" или "будет подставлено" нужно смотреть, какой именно код записан в выражении. С этим моментом связана известная проблема неоднозначности выражений. Забежав вперед, можно рассмотреть связанный с данным вопросом пример применения операторов в выражении:

<source lang="kpp"> var i = 5; var x = ++i + ++i; </source>

Как вы думаете, какое значение будет иметь переменная x после выполнения вышеприведенного кода? Программист, знающий только Паскаль при виде этого примера скорее всего впадет в ступор, поскольку этот язык не имеет оператора ++, либо он сочтет что выражение записано ошибочно.

Новичок, изучающий язык C++, но уже кое-что знающий о нем, может рассуждать так: «Оператор ++ — это оператор инкремента. В зависимости от того где он расположен в выражении, будет зависеть то как он изменяет переменную; если оператор находится слева он переменной, то сначала будет произведена операция инкремента, а затем новое значение будет использоваться при расчете выражения. В нашем случае это именно так. Стало быть, при рассчете выражения, в обоих случаях значение переменной i будет увеличено на единицу и будет использовано в рассчете. В результате мы получим выражение x = 6 + 7 = 13»

Опытный программист на C++, первым делом спросит как реализованы операторы ++ и +, и происходит ли копирование аргументов. Если копирование происходит, то значение будет таким же как у новичка, то есть 13. Если же оператор работает с самой переменной, то произойдет следующее:

Первый оператор ++ увеличит значение переменной i на единицу, которое теперь будет равно 6. Поскольку мы имеем дело со ссылкой на переменную то это значение не будет нигде сохраняться. Далее, при вычислении значения второго слагаемого сработает уже второй оператор ++, который так же увеличит (уже увеличенное значение!) переменную на 1, и вернет результат 6 + 1, то есть 7. При вычислении итогового значения мы получаем выражение 7 + 7, то есть 14.

Получается что сколько человек, столько и мнений. А самое интересное, что каждый из них прав. Их рассуждения логичны с учетом того, с какой позиции смотреть на проблему. В такой неразберихе не мудрено запутаться. Если читатель еще не сбит с толку окончательно, то можно продолжить и рассмотреть эту задачу с точки зрения языка К++.

В случае с языком К++ вычисление значения будет происходить по второму сценарию. То есть, результат такого выражения будет равен 14.

Вызов функций

Вызов функций в выражениях осуществляется путем записи имени функции, следом за которым в круглых скобках перечисляются ее аргументы. При этом, при вычислении выражения, вместо самой функции будет подставлено ее значение:

<source lang="kpp"> const pi = 3.1415926; var x = 10; var y = x * sin(pi); </source>

Доступ к полям

Доступ к полям и свойствам классов осуществляется путем записи имени объекта, следом закоторым ставится оператор точка ".", а затем идентификатор поля либо метода. Если ссылаемое поле само имеет свойства или поля, то к ним так же можно ссылаться, поставив вторую точку и указав идентификатор и т. д.

<source lang="kpp" line="1"> class MyClass {

   var m_Field = "hello world";
   property field read m_Field write m_Field;
   public function SetField(const string what = "world") {
       m_Field = "hello " + what;
   }

}

function caller() {

   var object = new MyClass;
   puts(object.field);
   object.field = "hello everyone!";
   object.SetField("universe");
   object.SetField();

} </source>


1-7
Мы объявляем некоторый класс MyClass, который имеет поле m_Field и свойство field, связанное с полем. Так же имеется метод SetField(), который устанавливает новое значение свойства, которое определяется выражением в строке 5. Значение свойства складывается из строковой константы "hello ", к которой добавляется значение параметра what.
9-15
В этой функции приводится пример применения вышеописанного класса. Сначала мы создаем инстанцию класса MyClass с помощью оператора new. Затем вызывается функция puts(), которая печатает значение свойства объекта. В третьей строке мы присваиваем свойству field (а значит и полю m_Field) новое значение. Последние две строки показывают пример вызова метода с явным аргументом и с аргументом по умолчанию.

Good points all aorund. Truly appreciated.

Персональные инструменты
Пространства имён

Варианты
Действия
Навигация
информация
документация
Инструменты