Объектно-ориентированное программирование (en)[править заголовок, править ссылку на оригинал, править текст, править список подразделов, править список разделов] Начиная с версии 3.00 m предлагает следующие возможности ООП.
Классы и экземпляры классов (en)[править заголовок, править ссылку на оригинал, править текст] Класс — объявление связанных переменных (полей) и функций ("методов"), их обрабатывающих. Класс только описывает тип шаблона; данные создаются при создании экземпляра класса. Классы могут основываться на существующих классах, наследуя все их поля и функции. Наследуемые функции могут быть переопределены, чтобы изменить поведение или функциональность, предлагаемые классом. Класс объявляется ключевым словом class Sum
s
function add(x)
s+=x
end
function res()
return s
end
end
Это объявляет класс Класс всегда принадлежит модулю, в котором объявлен (он может быть встроенным модулем или основным скриптом). Поэтому класс уникально определяется модулем, в котором объявлен, и его именем внутри модуля: если класс Класс должен быть объявлен перед тем, как может быть использован. Это означает, что если два класса ссылаются друг на друга, по крайней мере один должен быть объявлен с использованием class C forward // даем знать о C без подробностей
class D
x: C // C может быть использован, но C.y не виден
end
class C // определяем C
y
function f(d: D)
return y*d.x.y
end
end
Объявление переменных (дополнение) (en)[править заголовок, править ссылку на оригинал, править текст] Переменная может быть объявлена так, чтобы ссылаться на экземпляры заданного класса (или быть x:Sum=null Переменная не может быть переопределена или определена не полностью: первое встречающееся присваивание в исходном коде должно определять ее тип, или она останется неопределенного типа (как и обычная переменная в m). Всякий раз, когда выражение присваивается переменной определенного класса, присваиваемое значение проверяется. Если оно не является экземпляром соответствующего класса и не x:Sum=null a=23*7 x=a // a содержит число, не экземпляр класса Sum → возникло ExcNotSuchInstance Объявление функций (дополнение) (en)[править заголовок, править ссылку на оригинал, править текст] Параметры функций похожи на локальные переменные и могут быть определены так, чтобы содержать экземпляры заданного класса. Например, функция для умножения экземпляра function multiply(s: Sum, f): Sum ... end Как и в случае присвоения переменным определенного класса, присваиваемые параметрам значения проверяются при вызове функции, и возвращаемое значение проверяется при выходе из функции: multiply("no sum", 3)
→ возникло ExcNotSuchInstance
function getsum(): Sum
return "тоже не sum"
end
y=getsum()
→ возникло ExcNotSuchInstance
Поля класса (en)[править заголовок, править ссылку на оригинал, править текст] Полезный класс обычно содержит поля, т.е. переменные, которые включает каждый экземпляр класса. Поля объявляются просто перечислением их имен в теле класса, возможно, разделенные точкой с запятой. Поле должно быть описано до того, как можно будет на него сослаться в функции. Когда экземпляр создается, все поля приравниваются Обращение к полям класса происходит так:
s:Sum=... s.s=0
sums=[...] print sums[3].(Sum)s // доступ к s требует приведения
Функции класса (en)[править заголовок, править ссылку на оригинал, править текст] Большинство классов также содержат функции. Функции класса работают с экземпляром, тотчнее с его полями. Например, функция Внктри функции класса class C
x
function setx(x)
this.x=x // присвоить параметр x полю x
end
end
Правила вызова функции класса такие же, как при доступе к полям класса:
s:Sum=... s.add(3) // вызывает add для s
sums=[...] sums[3].(Sum)add(4) // требует приведения Sum
class Sum
...
function addtwice(x)
// то же, что и this.add(x); this.add(x)
add(x); add(x)
end
end
Есть два способа определить функцию класса: либо внутри тела класса, либо объявления ее как class C forward // даем знать о C без подробностей class D x: C // C может быть использован, но C.y не виден function mult(a) forward end class C // описываем C y end function D.mult(a) // C определен, теперь определяем D.mult return x.y*a end Далее показано как переопределить функции класса в подклассе.
Наследование, под- и суперклассы (en)[править заголовок, править ссылку на оригинал, править текст] Одно из ключевых свойств классов и их растяжения: новые классы могут быть определены, основываясь на существующих классах, наследуя их поля и функции. Переопределяя функции, можно изменить или расширить поведение экземпляров класса. Чтобы определить новый класс, расширяющий существующий класс, добавьте class Avg is Sum
n // счетчик элементов для вычисления среднего
function add(x) // переопределение Sum.add()
s+=x; n++
end
function res() // переопределение Sum.res()
return s/n
end
function count()
return n
end
end
Это устанавливает следующую простую иерархию классов:
Поскольку, <ocde>Avg</code> расширяет Функции суперклассов всегда доступны через встроенный параметр function add(x) // переопределение Sum.add() super.add(x); n++ end function res() // переопределение Sum.res() return super.res()/n end Определяя функцию класса как class Aggregator function add(x) forward function res() forward end class Sum is Aggregator ... Создание экземпляров и конструкторы (en)[править заголовок, править ссылку на оригинал, править текст] Определение класса определяет функцию с таким же именем, функцию его создающую. Вызов этой функции обладает следующими эффектами:
// создать новый экземпляр Sum и присвоить его x x:Sum=Sum() print x → .Sum(s=null) При определении (переопределении) функции class Sum
s
function init()
s=0
end
function add(x)
...
end
x:Sum=Sum()
print x
→ .Sum(s=0)
Функция class Person
name
height
function init(name="unknown",height=180)
this.name=name; this.height=height
end
end
print Person()
→ .Person(name=unknown,height=180)
print Person("Lucky Luke")
→ .Person(name=Lucky Luke,height=180)
print Person("Joe",155)
→ .Person(name=Joe,height=155)
Заметим, что в m нет функции деструктора. Экземпляры класса, которые больше не нужны, автоматически удаляются сборщиком мусора без явной очистки.
Базовый класс .Instance (en)[править заголовок, править ссылку на оригинал, править текст] Есть единственный базовый класс class Instance function init() end end Поэтому два следующих объявления эквивалентны class Sum ... end class Sum is .Instance ... end Даже хотя нет большой разницы, предпочтительней корректно создавать экземпляр x:.Instance=.Instance() Ссылки на функции экземпляра (en)[править заголовок, править ссылку на оригинал, править текст] Ссылка на функцию экземпляра похожа на ссылку на функцию (см. раздел Ссылки на функции (en)), но всегда работает с заданным экземпляром, определяемым при получении ссылки. Ссылки на функции экземпляров наиболее полезны для реализации обратного вызова в объектно-ориентированной среде, например, слушателей событий. Иногда их также называют "делегаты" или "делегирующие функции", поскольку ссылки на функции работают как делегаты экземпляра, посланные другому экземпляру. Рассмотрим следующую передачу значений в массиве function consume(a, c)
for v in a do
c(v)
end
end
function out(n)
print n
end
consume([7,-8,9], &out) // ссылка на обычную функцию
→ 7
-8
9
s:Sum=Sum()
consume([7,-8,9], s.&add) // ссылка на функцию экземпляра
print s, s.res()
→ .Sum(s=8), 8
Второй вызов
© 2004-2009 airbit AG, CH-8008 Zürich
|
|