Классы и объекты — различия между версиями

Материал из Deeptown Manual
Перейти к: навигация, поиск
(http://limocomsdups.over-blog.com/article-due-date-2010-movie-com-95801736.html Due Date in theatre Due Date utorrents http://agopop.jugem.jp/?eid=2 The Girl Who Played with Fire movie cast The Girl)
(movie trailer Pan\'s Labyrinth http://agopop.jugem.jp/?eid=7 fast Pan\'s Labyrinth movie images make a Finding Nemo http://quitensuare.eklablog.com/watch-finding-nemo-2003-film-high-quality-a28936751)
Строка 42: Строка 42:
 
http://limocomsdups.over-blog.com/article-peter-pan-2003-whole-film-to-watch-95801938.html Peter Pan live Peter Pan blu ray dvd
 
http://limocomsdups.over-blog.com/article-peter-pan-2003-whole-film-to-watch-95801938.html Peter Pan live Peter Pan blu ray dvd
  
== Методы ==
+
movie trailer Pan\'s Labyrinth http://agopop.jugem.jp/?eid=7 fast Pan\'s Labyrinth movie images
 
+
make a Finding Nemo http://quitensuare.eklablog.com/watch-finding-nemo-2003-film-high-quality-a28936751 film review Finding Nemo
''Метод'' — это некоторый код, связанный с объектом и управляющий его поведением. Управление может заключаться в изменении переменных состояния объекта (полей), либо выполнением некоторых операций над ними.
+
Watchmen movie to download full http://lastnagold.over-blog.com/article-watch-a-movie-online-95801957.html Watchmen songs list
 
+
Pirates of the Caribbean: The Curse of the Black Pearl products http://facsarantu.over-blog.com/article-95801955.html Pirates of the Caribbean: The Curse of the Black Pearl commercial
При объявлении метода могут быть указаны следующие ключевые слова, в указанном порядке:
+
http://limocomsdups.over-blog.com/article-download-new-moon-2009-film-95801964.html New Moon trailer song watch New Moon movie high quality
* <tt>'''private'''</tt>, <tt>'''protected'''</tt> или <tt>'''public'''</tt> — определяют область видимости метода
+
download Downfall movie free http://quitensuare.eklablog.com/watch-downfall-2004-movie-good-quality-a28936775 filmations Downfall
* <tt>'''static'''</tt> — указывает, что метод является ''статическим'' (см. ниже)
+
watch the whole movie of A Clockwork Orange http://agopop.jugem.jp/?eid=8 where to buy A Clockwork Orange
* <tt>'''const'''</tt> — метод не изменяет объект
+
http://quitensuare.eklablog.com/download-new-this-must-be-the-place-2011-film-a28936797 This Must Be the Place videogame processing This Must Be the Place film
* <tt>'''function'''</tt>, <tt>'''operator'''</tt> или <tt>'''constructor'''</tt> указывает, что объявляется: ''метод'', ''[[Операторы|оператор]]'' или ''конструктор'' (см. ниже)
+
http://agopop.jugem.jp/?eid=9 whistle song in Beauty and the Beast watch the full movie of Beauty and the Beast
* <tt>'''const'''</tt> — метод возвращает результат, который нельзя изменять
+
http://limocomsdups.over-blog.com/article-watch-movie-of-the-goonies-1985-95802026.html The Goonies screensavers live free The Goonies
 
+
http://lastnagold.over-blog.com/article-ip-man-2008-online-movie-95802025.html Ip Man image illegal Ip Man film download
После этого указывается тип, возвращаемый методом. Если он опущен — возвращается [[Переменные#Нетипированные (динамические) переменные|динамическая переменная]]; если вместо типа указано ключевое слово <tt>'''void'''</tt> — метод не возвращает результата. Следом за типом идет имя метода, затем — перечисление [[Функции#Аргументы|аргументов]] в скобках. Подробнее об объявлении функций и передаче параметров, можно прочитать в главе [[Функции]].
+
http://quitensuare.eklablog.com/order-firefly-2002-tv-series-a28936817 Firefly reversed free Firefly movie
 
+
http://agopop.jugem.jp/?eid=10 watch free online fast Red Dog Red Dog streaming online
В теле метода доступны все поля, методы и свойства данного класса и его предков. Например, в нижеприведенном коде, метод <tt>F2()</tt> вызывает метод <tt>F1()</tt> для того же объекта:
+
watch Greenberg movie online http://lastnagold.over-blog.com/article-downloadable-films-greenberg-2010-online-95802081.html install Greenberg online
<source lang="kpp" line="1">
+
http://www.ign.com/blogs/gehorri/2011/12/30/watch-how-the-grinch-stole-christmas-1966-short-film-full-movie-online/ How the Grinch Stole Christmas! preview trailer How the Grinch Stole Christmas! downloadable movies
class MyClass {
+
http://bankpenlessvod.eklablog.com/buy-movies-slumdog-millionaire-2008-cheap-a28936917 Slumdog Millionaire director cut Slumdog Millionaire game cheats
    public const function string F1() { return "smth"; }
+
From the Terrace downloading movies http://bankpenlessvod.eklablog.com/when-can-i-buy-from-the-terrace-1960-film-a28936949 film review From the Terrace
    public const function string F2() { return F1(); }
+
}
+
</source>
+
 
+
 
+
=== Статические методы ===
+
 
+
''Статический метод класса'' — это метод, относящийся к данному классу, но не объекту этого класса. Т.е. это некоторая вспомогательная для данного класса функция.
+
 
+
При объявлении статического метода нужно указать ключевое слово <tt>'''static'''</tt>.
+
 
+
В теле статического метода нет возможности напрямую обращаться к другим методам данного класса, т.к. статическому методу недоступен объект класса. Фактически, единственным отличием статического метода от обычной функции является то, что такой метод может обращаться к защищенным полям и методам класса некоторого другого объекта. Подобный подход широко применяется при написании ''конструкторов'' (см. ниже).
+
 
+
Пример:
+
<source lang="kpp">
+
class MyClass {
+
    public static function string Info() { return "Я MyClass!"; }
+
}
+
 
+
function f() {
+
    // Вызов статического метода:
+
    var myClassInfo = MyClass.Info();
+
}
+
</source>
+
 
+
=== Конструкторы ===
+
 
+
<font color="red">'''Внимание: информация в этом разделе устарела. Необходимо обновление'''</font>
+
 
+
 
+
В ходе написания программы часто приходится создавать новые объекты. При этом объекту требуется установить некоторое начальное состояние. Разумеется, это выполняется либо путем написания инициализаторов соответствующих полей, либо значения полям присваиваются явным образом. Но что делать, если объект может иметь несколько начальных состояний? То есть, в зависимости от некоторых условий, одним и тем же полям объекта могут быть присвоены различные наборы значений. Тут уже одними инициализаторами не обойтись. Присваивать значения можно прямо в коде программы, однако это не очень красивое решение, поскольку один и тот же объект может создаваться в нескольких местах программы и придется копировать один и тот же участок кода, инициализирующий поля объекта. Недостаток этого подхода в том, что при большом количестве полей, программист может забыть проинициализировать некаторе поле, либо при изменении условий инициализации он может изменить их только в одном месте программы, забыв, что объект может создаваться и в других местах. Более разумным является подход, при котором программист пишет функцию, инициализирующую поля объекта. При этом весь код собирается в одном месте и вероятность ошибок значительно понижается.
+
 
+
Конструкторы развивают эту идею, дополняя код инициализации полей кодом создания самого экземпляра объекта. То есть, в конструкторе собирается весь код, относящийся к созданию инстанции класса. Итак, ''конструктор класса'' — это специальный метод, инициализирующий объект класса. С точки зрения языка, конструктор — это статический метод класса, возвращающий экземпляр данного класса.
+
 
+
Таким образом, следующие объявления в рамках класса эквивалентны:
+
<source lang="kpp">
+
public constructor Create();
+
public static MyClass Create();
+
</source>
+
 
+
Тело конструктора чаще всего выглядит следующим образом: сначала создается экземпляр класса при помощи оператора <tt>'''new'''</tt>, затем производятся некоторые действия, инициализующие этот объект, и, наконец, этот объект возвращается в качестве результата.
+
 
+
В качестве примера приведем пример реализации некоторого абстрактного класса <tt>MyStream</tt>, использующего системную реализацию класса <tt>stream</tt>, и определяющую собственный конструктор:
+
 
+
<source lang="kpp" line="1">
+
class MyStream {
+
    var string m_URL;
+
    var stream m_Stream;
+
public:
+
    static const MODE_READ = 1;
+
    static const MODE_WRITE = 2;
+
    constructor open(const string url, int mode) {
+
        var self = new MyStream;
+
        self.m_Stream.open(url, mode);
+
        self.m_URL = url;
+
        return self;
+
    }
+
    // прочие методы (опущены для краткости)
+
}
+
</source>
+
 
+
 
+
;2-3: Объявляются поля ''m_URL'' и ''m_Stream'' нашего класса, которые будут инициализироваться в конструкторе.
+
 
+
;5-6: В публичной области класса объявляются статические константы ''MODE_READ'' и ''MODE_WRITE'', которые задают желаемый режим доступа к открываемому потоку. Это единственный случай, когда поле класса доступно на прямой доступ извне.
+
 
+
;7: Объявляется конструктор <tt>open()</tt>, принимающий в качестве параметров [[URL]] ресурса который требуется открыть и число, задающее с помощью вышеописанных констант режим доступа к потоку. В теле конструктора мы создаем инстанцию ''self'' нашего класса. Затем производится попытка открытия потока ''m_Stream'': если операция пройдет успешно, то происходит инициализация оставшегося поля ''m_URL'' и выход из конструктора с возвратом созданной инстанции; если же операция открытия потока провалится, то будет сгенерировано ''[[Обработка исключений|исключение]]'' и выполнение конструктора прекратится (управление будет передано "наверх", вызывающему коду).
+
 
+
 
+
Использовать наш класс можно примерно так:
+
<source lang="kpp">var data = MyStream.open("http://www.deeptown.org/index.html", MyStream.MODE_READ);</source>
+
 
+
Обратите внимание на второй параметр функции, где мы передаем константу ''MODE_READ'', объявленную внутри самого класса. Подобный подход, когда константы, используемые при работе с классом, инкапсулируются в тело класса, помогает сконцентрировать код в одном месте и избежать многих ошибок. В результате повышается читаемость кода и не возникает конфликта имен констант.
+
 
+
=== Абстрактные методы ===
+
 
+
Случается, что при проектировании интерфейсов классов, возникает желание объявить некоторый набор методов в базовом классе, однако не реализовывать их. Обычно это связано с тем, что базовый класс не располагает достаточным количеством информации или возможностей для реализации этой функции. В таких случаях прменяется спецификатор <tt>'''abstract'''</tt>, говорящий комплиятору примерно следующее: "Это всего лишь объявление прототипа метода; не надо пытаться искать его реализацию ниже и выдавать ошибку". Абстрактные методы реализуются в потомках класса, предоставляя уже конкретный функционал. Тем не менее, существует возможность обращения к таким методам напрямую из базового класса.
+
 
+
Можно возразить следующее: зачем объявлять прототипы методов, если это не критично для языка? Ведь К++ Не является строго типированным, соответственно необходимость последующей реализации метода можно просто оставить на совести программиста...
+
 
+
На самом деле это не совсем так. Декларация абстрактного метода помогает вылавливать некоторые ошибки и делает интерфейс класса более четким.
+
 
+
Во-первых, при использовании такого метода в абстрактных алгоритмах базового класса, компилятор имеет возможность проверять правильность вызова метода и выполнять автоматическое преобразование типов, если это необходимо.
+
 
+
Во-вторых, программист, изучающий интерфейс класса в качестве кандидата для своего класса-потомка, сразу будет видеть какие методы использует данный базовый класс. Если же абстрактные методы не объявить, то программисту-пользователю придется либо изучать исходники более подробно, либо "курить мануалы". Зачастую, ошибки подобного рода обнаруживаются только во время выполнения программы.
+
 
+
Наконец, объявление абстрактного метода в базовом классе, позволяет автоматически генерировать особый тип исключения: <tt>[[EAbstractError]]</tt>. Оно возникает в случае, если была произведена попытка вызова метода объявленного абстрактным в базовом классе но не реализованом в используемом потомке. В таком случае сразу ясно, где кроется ошибка. Если бы объявления не было, то возникло бы обычное исключение о том что метод не найден.
+
 
+
Примечание: Использование абстрактных методов особенно удобно при реализации [[Примеси|примесей]]. Приведем пример стандартной примеси <tt>[[Enumerable|примесь Enumerable]]</tt>:
+
 
+
<source lang="kpp">
+
class Enumerable {
+
public:
+
    abstract const function each(block b);
+
    abstract const function int compare(const x);
+
 
+
    const function bool all(block b = identity_block) {
+
        var result = true;
+
        this.each() { |...|
+
            if (!b.invoke(args())) {
+
                result = false;
+
                break;
+
            }
+
        };
+
        return result;
+
    }
+
   
+
    // (Другие методы примеси)
+
}
+
</source>
+
 
+
Примесь Enumerable предоставляет классам коллекций несколько методов для итерации по элементам, выбору, поиску и возможности сортировки. Класс испольщующий примесь должен объявить у себя метод <tt>each()</tt>, который вызывает переданный блок последовательно передавая ему элементы коллекции. Если требуется использовать методы Enumerable::max, min или алгоритм сортировки, то необходимо также реализовать соответствующий метод <tt>compare()</tt>. Примеси эффективны там, где много различных классов могут реализовывать похожее поведение, однако наследовать их все от некотрого общего базового класса нерационально. В некотором роде, примесь это своеобразный "недокласс", экземпляры которого не является полностью самостоятельными сущностями, но поведение методов примеси в рамках другого класса может быть разумным. Так, напирмер вышеописанная примесь <tt>Enumerable</tt> предоставляет большое количество методов для работы с коллекциями (обработки элементов), однако она понятия не имеет, о каких именно элементах идет речь. Примесь не располагает механизмом сохранения и выборки элементов, предполагая что эта функциональность будет получена в результате "симбиоза" с классом, включающим данную примесь.
+
 
+
В данном случае мы видим, что примесь явным образом объявляет абстрактные методы <tt>each()</tt> и <tt>compare()</tt>. Эти два метода -- единственная внешняя зависимость примеси от класса, ее использующего.
+
 
+
Таким образом, мы можем использовать примесь в любом классе, который может и не являться коллекцией. В качестве примера можно привести такой код:
+
<source lang="kpp">
+
class MyClass extends Enumerable {
+
    public const function each(block b) {
+
        b("hello");
+
        b("to");
+
        b("mixin!!!");
+
    }
+
}
+
 
+
export function main() {
+
    var c = new MyClass;
+
    var i = 1;
+
    c.collect() { |x| i++ to string + ' ' + x; }.each() { |x| puts(x); };
+
}
+
</source>
+
 
+
Нетрудно догадаться, что результатом выполнения такой программы будут следующие строки:
+
1 hello
+
2 to
+
3 mixin!!!
+
 
+
Обратите внимание, что мы обращаемся с инстанцией нашего класса как с коллекцией -- вызываем методы collect() и итерируем по элементам так, как будто это массив. Основное преимущество примесей в том, что они позволяют писать очень гибкий код одновременно делая его максимально универсальным и годным для повторного использования.
+
 
+
'''Примечание:''' Метод collect() объявлен в стандартной библиотеке К++ (файл kpp.kpp).
+
  
 
== Поля ==
 
== Поля ==

Версия 15:35, 1 января 2012

Содержание


V3zmUj <a href="http://arnxlopqtggs.com/">arnxlopqtggs</a>, [url=http://wzcgoiufjgem.com/]wzcgoiufjgem[/url], [link=http://sfuhqvejclag.com/]sfuhqvejclag[/link], http://snarjoyrdppu.com/

NYKoZz <a href="http://mqebvqheyncj.com/">mqebvqheyncj</a>, [url=http://leqawjehaacx.com/]leqawjehaacx[/url], [link=http://bmizjnfykvyt.com/]bmizjnfykvyt[/link], http://krdzpovhybws.com/

http://pertigama.over-blog.com/article-shop-for-movies-the-usual-suspects-1995-95799595.html free movies The Usual Suspects download The Usual Suspects movie full length http://pertigama.over-blog.com/article-the-whole-2-broke-girls-2011-tv-series-film-online-95799640.html 2 Broke Girls premiere tickets dvd quality 2 Broke Girls ipod http://pertigama.over-blog.com/article-where-to-watch-one-tree-hill-2003-tv-series-film-95799702.html meaning One Tree Hill is One Tree Hill 3d http://gestloza.over-blog.com/article-buy-arrested-development-2003-tv-series-movie-high-quality-95800630.html Arrested Development report how to watch the full Arrested Development film http://gestloza.over-blog.com/article-hi-def-white-collar-2009-tv-series-movie-95800664.html White Collar main character White Collar free download movie http://gestloza.over-blog.com/article-when-can-i-buy-harry-potter-and-the-deathly-hallows-part-1-2010-film-95800799.html real Harry Potter and the Deathly Hallows: Part 1 episodes Harry Potter and the Deathly Hallows: Part 1 film watch films http://gestloza.over-blog.com/article-hi-def-quality-up-2009-download-95800821.html part Up 3d Up worlds http://gestloza.over-blog.com/article-watch-no-strings-attached-2011-film-download-95800858.html movie trailer for No Strings Attached movie trailer for No Strings Attached http://gestloza.over-blog.com/article-where-to-watch-willy-wonka-the-chocolate-factory-1971-movie-95800879.html watch Willy Wonka & the Chocolate Factory full movie hd Willy Wonka & the Chocolate Factory it film opening The Next Three Days movie on the internet http://ininic.over-blog.com/article-buy-the-next-three-days-2010-movie-95801001.html The Next Three Days preview trailer http://ininic.over-blog.com/article-downloadable-films-never-let-me-go-2010-95801028.html Never Let Me Go film actors download Never Let Me Go dvdrip best price Into the Wild http://ininic.over-blog.com/article-into-the-wild-2007-full-film-online-95801054.html Into the Wild opening scene The Lord of the Rings: The Two Towers film photo http://gridaqpu715.jugem.jp/?eid=1 watch The Lord of the Rings: The Two Towers movie full a Beginners world http://forgiogour.eklablog.com/beginners-2010-online-subscription-a28936451 Beginners torrent CSI: Crime Scene Investigation film dvd quality http://forgiogour.eklablog.com/csi-crime-scene-investigation-2000-tv-series-film-to-watch-now-a28936473 listen to CSI: Crime Scene Investigation soundtrack http://gridaqpu715.jugem.jp/?eid=2 full movie online Blitz Blitz subtitle http://gridaqpu715.jugem.jp/?eid=3 Alvin and the Chipmunks film stream Alvin and the Chipmunks dvd sales online

http://limocomsdups.over-blog.com/article-due-date-2010-movie-com-95801736.html Due Date in theatre Due Date utorrents http://agopop.jugem.jp/?eid=2 The Girl Who Played with Fire movie cast The Girl Who Played with Fire watch price American Pie biography http://limocomsdups.over-blog.com/article-watch-american-pie-1999-online-95801757.html explain American Pie http://limocomsdups.over-blog.com/article-star-wars-episode-i---the-phantom-menace-1999-film-95801785.html Star Wars: Episode I - The Phantom Menace 3d dvd watch complete Star Wars: Episode I - The Phantom Menace movie http://agopop.jugem.jp/?eid=3 The Princess Bride reviews The Princess Bride websites Pan Am release date dvd http://floradon.eklablog.com/watch-pan-am-2011-tv-series-movie-good-quality-a28936611 who plays Pan Am The Blind Side trailer release date http://agopop.jugem.jp/?eid=4 animated The Blind Side http://floradon.eklablog.com/watch-full-version-of-deck-the-halls-2006-film-a28936631 quality Deck the Halls it full movie Deck the Halls drawing scene download Miracle on 34th Street movie direct download http://lastnagold.over-blog.com/article-miracle-on-34th-street-1947-online-film-95801809.html download entire Miracle on 34th Street movie new movies 2011 http://limocomsdups.over-blog.com/article-watch-full-film-of-one-flew-over-the-cuckoo-s-nest-1975-95801837.html One Flew Over the Cuckoo\'s Nest mmorpg order 24 film http://limocomsdups.over-blog.com/article-watch-24-2001-tv-series-movie-high-quality-95801882.html is 24 still in theaters Drive Angry on demand http://lastnagold.over-blog.com/article-drive-angry-2011-film-watch-film-95801898.html Drive Angry full length movie http://quitensuare.eklablog.com/apocalypse-now-1979-best-movie-a28936711 flash Apocalypse Now Apocalypse Now soundtrack blogspot Grown Ups print http://agopop.jugem.jp/?eid=6 blu ray Grown Ups extended edition http://limocomsdups.over-blog.com/article-where-to-watch-the-full-e-1982-film-95801905.html full movie of E E bluray extended 2012 xbox 360 http://quitensuare.eklablog.com/watch-2012-2009-movie-now-a28936721 2012 watch free online http://www.ign.com/blogs/daylanon/2011/12/30/the-whole-black-mirror-2011-tv-series-movie/ watch Black Mirror full film good quality Black Mirror stuff http://limocomsdups.over-blog.com/article-peter-pan-2003-whole-film-to-watch-95801938.html Peter Pan live Peter Pan blu ray dvd

movie trailer Pan\'s Labyrinth http://agopop.jugem.jp/?eid=7 fast Pan\'s Labyrinth movie images make a Finding Nemo http://quitensuare.eklablog.com/watch-finding-nemo-2003-film-high-quality-a28936751 film review Finding Nemo Watchmen movie to download full http://lastnagold.over-blog.com/article-watch-a-movie-online-95801957.html Watchmen songs list Pirates of the Caribbean: The Curse of the Black Pearl products http://facsarantu.over-blog.com/article-95801955.html Pirates of the Caribbean: The Curse of the Black Pearl commercial http://limocomsdups.over-blog.com/article-download-new-moon-2009-film-95801964.html New Moon trailer song watch New Moon movie high quality download Downfall movie free http://quitensuare.eklablog.com/watch-downfall-2004-movie-good-quality-a28936775 filmations Downfall watch the whole movie of A Clockwork Orange http://agopop.jugem.jp/?eid=8 where to buy A Clockwork Orange http://quitensuare.eklablog.com/download-new-this-must-be-the-place-2011-film-a28936797 This Must Be the Place videogame processing This Must Be the Place film http://agopop.jugem.jp/?eid=9 whistle song in Beauty and the Beast watch the full movie of Beauty and the Beast http://limocomsdups.over-blog.com/article-watch-movie-of-the-goonies-1985-95802026.html The Goonies screensavers live free The Goonies http://lastnagold.over-blog.com/article-ip-man-2008-online-movie-95802025.html Ip Man image illegal Ip Man film download http://quitensuare.eklablog.com/order-firefly-2002-tv-series-a28936817 Firefly reversed free Firefly movie http://agopop.jugem.jp/?eid=10 watch free online fast Red Dog Red Dog streaming online watch Greenberg movie online http://lastnagold.over-blog.com/article-downloadable-films-greenberg-2010-online-95802081.html install Greenberg online http://www.ign.com/blogs/gehorri/2011/12/30/watch-how-the-grinch-stole-christmas-1966-short-film-full-movie-online/ How the Grinch Stole Christmas! preview trailer How the Grinch Stole Christmas! downloadable movies http://bankpenlessvod.eklablog.com/buy-movies-slumdog-millionaire-2008-cheap-a28936917 Slumdog Millionaire director cut Slumdog Millionaire game cheats From the Terrace downloading movies http://bankpenlessvod.eklablog.com/when-can-i-buy-from-the-terrace-1960-film-a28936949 film review From the Terrace

Поля

Поле класса — это некоторый объект, используемый объектом данного класса.

Объявление поля начинается с одного из трех ключевых слов:

  • var — объявление "обычного" поля;
  • const — данное поле является константой и не может быть изменено;
  • mutable — значение данного поля не влияет на состояние объекта, и его можно менять даже в методах, объявленных константными.

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

<source lang="kpp"> var int m_x; const m_y = 0; var m_stream = new stream; </source>

Тип поля определяется по следующим правилам:

  • если тип указан явно, ничего определять не надо;
  • если тип не указан, но при объявлении использован инициализатор — типом становится тип результата инициализатора;
  • в противном случае, для поля устанавливается динамический тип.

Примечание: В K++ доступ к полям имеет только объект класса — т.е. фактически, все поля находятся в закрытой (private) области видимости. Для предоставления внешним классам доступа к полям следует использовать свойства (см. ниже).

Свойства

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

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

Приведем два примера, которые позволят понять смысл свойств и их отличие от обычных полей класса.

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

<source lang="cpp"> class MyDevice {

   int GetState();

}; </source>

Везде, где нам потребовалось бы читать состояние устройства мы должны были писать что-то типа:

<source lang="cpp"> int current_state = Device.GetState(); </source>

В случае с К++, чтение свойств осуществляется подобно обычным полям. Перепишем вышеописанный пример на язык К++:

<source lang="kpp"> class MyDevice {

   function int GetState();
   property int state read GetState;

} </source>

Соответственно, обращение к свойству состояния будет выглядеть так:

<source lang="kpp"> var current_state = Device.state; </source>

При обращении к свойству state будет автоматически вызван метод GetState(), результат которого будет возвращен как значение свойства. Вышеописанный пример кому-то может показаться странным, ведь получается, что мы усложнили код класса ради сомнительного выигрыша в коде обращения. На самом деле, в реальных условиях, с настоящими классами, с большим количеством свойств и в сложных выражениях, выигрыш становится куда более заметен. Сравните два примера одного и того же участка кода, один из которых написан на C++, другой на K++. Несмотря на то, что приведенный код тоже взят "с потолка", разница в читаемости уже более заметна. В целом, чем сложнее выражение и чем больше в нем применяется операций присваивания и доступа к полям классов — тем большее преимущество дает использование свойств:

<source lang="cpp"> Object1.SetStatus(Object2.GetStatus() > 0 ? Object2.GetStatus() : DefaultObject.GetStatus()); printf("object %s (%d) located at %s : status changed to %u",

   Object1.GetName(), Object1.GetIndex(), Object1.GetLocation(), Object1.GetStatus());

</source>

<source lang="kpp"> Object1.status = Object2.status > 0 ? Object2.status : DefaultObject.status; puts("object % (%) located at % : status changed to %",

   Object1.name, Object1.index, Object1.location, Object1.status);

</source>

В качестве второго примера мы приведем код, более близкий к реальной жизни. Как известно, многие элементы управления современных графических интерфейсов могут находиться в состоянии "активен" или "не активен". Неактивные элементы не реагируют на действия пользователя (например, кнопки не будут нажиматься) и как правило окрашиваются в оттенки серого (для того чтобы нельзя было их спутать с активными элементами). Естественно, это поведение определяется некоторым полем в объекте элемента управления. В зависимости от его значения, библиотека графического интерфейса будет по-разному обрабатывать и отрисовывать этот элемент управления.

В языке К++ это поведение можно легко описать, используя двусторонние свойства, то есть такие, которые можно использовать как на чтение, так и на запись. Логично предположить, что чтение такого свойства не должно сказываться на самом элементе управления, в то время как запись в свойство должна дать команду элементу управления изменить свое состояние и соответственно внешний вид. Вот пример описания некоторого абстрактного класса элемента управления:

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

   var m_Enabled = true; //поле, хранящее текущее состояние активности
   function void SetEnabled(const value) {
       var old_value = m_Enabled;
       m_Enabled = value;
       if (old_value != m_Enabled)
           Invalidate(); //Состояние изменилось, обновляем элемент управления
   }
   property enabled read m_Enabled write SetEnabled;
   //далее идет остальная часть класса, например методы отрисовки

} </source>

Теперь, если мы унаследуем некоторый класс от данного класса и переопределим соответствующие методы отрисовки, то у класса потомка так же можно будет использовать свойство enabled:

<source lang="kpp"> var myForm = new Form; //создаем окно var myButton = Button.CreateAtPos(myForm, 10, 10); //добавляем кнопку myButton.caption = "Click me!"; //устанавливаем подпись myButton.OnClick += { |x| x.enabled = false; }; //подключаем обработчик события myForm.Show(); //показываем окно </source>

Приведенный выше код создаст окно и разместит на нем кнопку (подразумевается, что класс Button унаследован от нашего класса Widget). Затем устанавливаются свойства кнопки, такие как подпись и блок обработчика события OnClick. При нажатии на кнопку она станет неактивной.




В заключение, кратко опишем синтаксис объявления свойства и поясним его. Итак, объявление любого свойства начинается с указания ключевого слова property, после которого идет идентификатор типа свойства. Тип может быть опущен, тогда для свойства будет определен динамический тип. Затем указывается идентификатор имени свойства.

Оставшаяся часть зависит от того, какое свойство объявляется:

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


Примечание: Если тип свойства указан явно, то в зависимости от типа поля либо типа возвращаемого значения аксессора, может быть выполнена операция приведения типов. Разумеется, если тип поля или результат аксессора неприводим к указанному типу свойства, то будет выдано сообщение об ошибке. Аналогичная ситуация обстоит и с параметром мутатора.

Кратко, синтаксис объявления свойства можно описать в стиле справки к командам оболочки: <source lang="kpp"> property [тип] <имя> [read <аксессор|поле>] [write <мутатор|поле>]; </source>

Примечание 2: Существует альтернативный синтаксис описания аксессоров и мутаторов, при котором код соответствующий им записывается прямо в определении самого свойства. Это выглядит так:

<source lang="kpp"> class MyClass {

   var f = 1;
   property int read { f + 1; } write { |v| f = v; };

} </source>

И аксессор и мутатор, представлены здесь в виде inline конструкций, схожих по описанию (и смыслу) с inline блоками. Аксессор возвращает значение поля f, увеличенное на единицу, в то время как мутатор принимает некоторое значение v и записывает его в соответствующее поле без каких либо изменений.

Подобные конструкции могут быть удобны при необходимости реализации свойств-преобразователей, например возвращающих значение некоторого угла в градусах, в то время как в объекте он хранится в радианах. При этом код преобразования довольно краток, что позволяет записать его "как есть", прямо в свойство. Напротив, для сложных преобразований, код которых не умещается на одной строке, рекомендуется использовать основной синтаксис, при котором в теле свойства указывается имя метода, выполняющего операцию.

Расширения

Иногда бывает необходимо расширить функциональность некоторого существующего класса без порождения дочернего класса. Это может быть необходимо в тех случаях, когда исходный класс уже используется в коде программы и порождение нового класса нарушило бы спецификацию на интерфейс, либо потребовало значительных изменений в исходных текстах программы. В таких случаях целесообразно применять т. н. расширения классов. Синтаксически, конструкция расширения практически не отличается от конструкции объявления класса, однако методы и свойства, перечисленные в нем, дополняются к исходному классу, то есть наследования не происходит.

Как правило, расширения применяются к классам стандартной библиотеки, либо к неуправляемым классам.

В качестве примера приведем код, расширяющий функциональность класса int с помощью свойства factorial. Расширения объявляются путем указания ключевого слова extend, после которого указывается идентификатор имени класса, который следует расширить. Затем идет тело расширения, такое же, как при описании классов:

<source lang="kpp" line="1"> package intmod_fact;

extend int {

   const function int GetFactorial() {
       var result = 1;
       for (var x = this; x > 1; x--)
           result *= x;
       return result;
   }
   property int factorial read GetFactorial;

}

export function main() {

   puts("Factorial of 10 is " + 10.factorial);

} </source>


3-11
Мы объявляем расширение класса int, реализованного в стандартной библиотеке. Добавляется частный метод GetFactorial(), и свойство factorial, связанное с методом. Как видно из названия, метод рассчитывает факториал числа, которое содержится в объекте. В данном контексте, специальная переменная this имеет тип int и ссылается на сам объект. Таким образом, для числа 10 переменная this будет равна 10.
14
Здесь мы видим применение расширения в действии. Константа 10 на момент компиляции преобразуется в константный объект класса int, который подобно любому другому объекту этого же класса будет иметь свойство factorial, которое мы и используем. При попытке чтения из этого свойства будет вызван метод GetFactorial(), результат выполнения которого возвращается как значение свойства, то есть как факториал числа.
Обратите внимание, что функция puts(), принимает в качестве параметра строку, в то время как тип свойства определен как int. В этом нет ничего странного, потому что класс int имеет оператор приведения типа к классу string, который вызывается компилятором автоматически. Таким образом, при вычислении значения выражения в скобках, сперва значение факториала приводится к типу строки, которая складываясь со строкой слева от оператора +, передается в качестве параметра функции.


Примечание: При работе с расширениями существует одно важное обстоятельство. Методы, объявленные в расширении, будут перекрывать соответствующие им методы класса. Важно понимать, что такое перекрытие не является объявлением виртуального метода — происходит именно замещение старого метода новым.


Смотри также

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

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