153 lines
9.4 KiB
HTML
153 lines
9.4 KiB
HTML
<html>
|
||
|
||
<head>
|
||
<object type="application/x-oleobject" classid="clsid:1e2a7bd0-dab9-11d0-b93a-00c04fc99f9e">
|
||
<param name="Keyword" value="operator">
|
||
<param name="Keyword" value="implicit">
|
||
<param name="Keyword" value="explicit">
|
||
<param name="Keyword" value="Перегрузка операций">
|
||
</object>
|
||
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
|
||
<title></title>
|
||
<link rel="StyleSheet" href="../../default.css">
|
||
<style type="text/css">
|
||
.auto-style1 {
|
||
color: #000080;
|
||
}
|
||
</style>
|
||
</head>
|
||
|
||
<body>
|
||
<H1>Перегрузка операций</H1>
|
||
<p>Перегрузка операций - это средство языка, позволяющее вводить
|
||
операции над типами, определяемыми пользователем. В <b>PascalABC.NET</b>
|
||
можно использовать только предопределенные значки операций.
|
||
Перегрузка операций для типа <code>T</code>, являющегося
|
||
классом или записью, осуществляется при помощи статической (классовой) функции-метода со
|
||
специальным именем <b><code>operator</code></b> <i>
|
||
ЗнакОперации</i>. Перегрузка специальных операций <code>+=</code>, <code>
|
||
-=</code>, <code>*=</code>, <code>/=</code>
|
||
осуществляется с помощью статической процедуры-метода, первый параметр
|
||
которой передается по ссылке.</p>
|
||
<p>Например:</p>
|
||
<blockquote>
|
||
<p><code><b>type</b> <br> Complex = <b>record</b><br> re,im: real;<br>
|
||
<strong>static</strong><b><span lang="en-us"> </span>function</b> <b>operator</b>+(a,b: Complex): Complex; <br>
|
||
<b>begin</b><br> Result.re := a.re + b.re;<br> Result.im := a.im + b.im;
|
||
<br> <b>end</b>; <br>
|
||
<strong>static</strong><b><span lang="en-us"> </span>function</b> <b>operator</b>=(a,b: Complex): boolean; <br> <b>begin</b><br> Result := (a.re = b.re)
|
||
<b>and</b> (a.im = b.im);<br> <b>end</b>; <br> <b>end</b>;</code></p>
|
||
</blockquote>
|
||
<p>Для перегрузки операций действуют следующие правила:</p>
|
||
<ol>
|
||
<li>Перегружать можно все операции за исключением
|
||
<code>@</code> (взятие адреса), <b><code>as</code></b>,
|
||
<code><b>is</b></code>, <code>new</code>. Кроме того,
|
||
можно перегружать специальные бинарные операции <code>+=</code>,
|
||
<code>-=</code>, <code>*=</code>, <code>/=</code>,
|
||
не возвращающие значений.</li>
|
||
<li>Перегружать можно только еще не перегруженные операции.</li>
|
||
<li>Тип по крайней мере одного операнда должен совпадать с
|
||
типом класса или записи, внутри которого определена операция.</li>
|
||
<li>Перегрузка осуществляется с помощью статической функции-метода,
|
||
количество параметров которой совпадает с количеством параметров
|
||
соответствующей операции (2 - для бинарной, 1 - для унарной).</li>
|
||
<li>Перегрузка операций <code>+=</code>, <code>-=</code>,
|
||
<code>*=</code>, <code>/=</code>
|
||
для соответствующих операторов
|
||
осуществляется с помощью статической процедуры-метода, первый параметр которой передается по
|
||
ссылке и имеет тип записи или класса, в котором определяется данная
|
||
операция, второй - передается по значению и совместим по присваиванию с
|
||
первым. Перегрузка остальных операций осуществляется с помощью статических
|
||
функций-методов. </li>
|
||
<li>Операции приведения типа <span lang="ru">задаются статическими
|
||
функциями, у которых </span>вместо имени <span lang="ru">используется </span>
|
||
<code><b>operator</b></code> <code><b>implicit</b></code> <span lang="ru">
|
||
(для неявного приведения типа) </span>и<span lang="ru">ли </span><code><b>
|
||
operator</b></code> <code><b>explicit</b></code> <span lang="ru">(для явного
|
||
приведения типа)</span>. </li>
|
||
</ol>
|
||
<p>Например:</p>
|
||
<blockquote>
|
||
<p><code><b>type</b> <br> Complex = <b>record</b><br>
|
||
...<br>
|
||
<strong>static</strong><b><span lang="en-us"> </span>function</b> <b>operator implicit</b>(d: real): Complex;<br>
|
||
<b>begin</b><br> Result.re := d;<br> Result.im := 0;<br>
|
||
<b>end</b>; <br>
|
||
<strong>static</strong><b><span lang="en-us"> </span>function</b> <b>operator explicit</b>(c: Complex): string;<br>
|
||
<b>begin</b><br> Result := Format('({0},{1})',c.re,c.im);<br>
|
||
<b>end</b>;<br>
|
||
<strong>static</strong><b><span lang="en-us"> </span>procedure</b> <b>operator</b>+=(<b>var</b> c: Complex;
|
||
value: Complex);<br> <b>begin</b><br>
|
||
c.re += value.re;
|
||
<br> c.im += value.im;<br>
|
||
<b>end</b>;<br>
|
||
<strong>static</strong><span lang="en-us"><b> </b> </span><b>function</b> <b>operator</b>+(c,c1: Complex):
|
||
Complex;<br> <b>begin </b><br>
|
||
Result.re := c.re + c1.re;
|
||
<br>
|
||
Result.im := c.im + c1.im;
|
||
<br>
|
||
<b>end</b>;<br> <b>end</b>;</code></p>
|
||
</blockquote>
|
||
<p>Можно перегружать операции с помощью <a href="extensionmethods.html">методов расширения</a> - в этом случае при
|
||
описании подпрограммы не следует писать слово static. Например, так в системном модуле
|
||
реализовано добавление числа к строке:</p>
|
||
<blockquote>
|
||
<p><code><strong>function</strong> <strong>operator</strong>+(str: string; n:
|
||
integer): string; <strong>extensionmethod</strong>;<br><strong>begin</strong><br>
|
||
Result := str +
|
||
n.ToString;<br><strong>end</strong>;</code></p>
|
||
</blockquote>
|
||
<p>При перегрузке операций методами расширения ключевое слово <code> <strong>extensionmethod</strong></code> можно не писать:</p>
|
||
<blockquote>
|
||
<p><code><strong>function</strong> <strong>operator</strong>+(str: string; n:
|
||
integer): string;<br><strong>begin</strong><br>
|
||
Result := str +
|
||
n.ToString;<br><strong>end</strong>;</code></p>
|
||
</blockquote>
|
||
<p>Можно перегружать расширенные операции присваивания +=, -= и т.д.: </p>
|
||
<blockquote>
|
||
<pre><code><strong>type</strong>
|
||
t0 = <strong>class
|
||
</strong> x: integer;
|
||
<strong>static</strong> <strong>function</strong> <strong>operator</strong>+=(a: t0; i: integer): t0;
|
||
<strong>begin</strong>
|
||
a.x += i;
|
||
<strong>end</strong>;
|
||
<strong>end</strong>;
|
||
<strong>begin</strong>
|
||
<strong>var</strong> t := new t0;
|
||
t += 2;
|
||
</code><span class="auto-style1"><font size="2"><strong>end</strong>.</font></span></pre>
|
||
</blockquote>
|
||
<p>Важно отметить, что если слева от расширенного присваивания находится
|
||
свойство, то перегруженная форма расширенного присваивания игнорируется и само
|
||
расширенное присваивание разворачивается в присваивание и соответствующую
|
||
операцию: </p>
|
||
<blockquote>
|
||
<pre><code><strong>type</strong>
|
||
t0 = <strong>class
|
||
</strong> x: integer;
|
||
<strong>static</strong> <strong>function</strong> <strong>operator</strong>+=(a: t0; i: integer): t0;
|
||
<strong>begin</strong>
|
||
a.x += i;
|
||
<strong>end</strong>;
|
||
<strong>end</strong>;
|
||
t1 = class
|
||
<strong>property</strong> p1: t0 <strong>read</strong> ...<strong> write</strong> ...;
|
||
<strong>end</strong>;
|
||
<strong>begin</strong>
|
||
<strong>var</strong> t := new t1;
|
||
t.p1 += 2;
|
||
</code><span class="auto-style1"><font size="2"><strong>end</strong>.</font></span></pre>
|
||
</blockquote>
|
||
<p>В данном коде последний оператор расширенного присваивания принудительно
|
||
развернется в </p>
|
||
<blockquote>
|
||
<pre><code>t.p1 := t.p1 + 2; </code></pre>
|
||
</blockquote>
|
||
<p>и поскольку для t0 не перегружена операция +, то компилятор выдаст ошибку.</p>
|
||
</body>
|
||
|
||
</html> |