Дж. Рамбо, М. Блаха - UML 2.0 - Объектно-ориентированное моделирование и разработка (1158633), страница 94
Текст из файла (страница 94)
Более того, возможность прослеживания связей модели классов также подразумевает существование определенных методов. Методы также возникают вследствие существования выводимых атрибутов, моделей состояний и взаимодействия. 1. Создание объекта (раздел 18А.1).
2. Существование объекта (раздел 18.4.2). 3. Уничтожение объекта (раздел 18.4.3). 4. Создание связи (раздел 18А.4). 5. Уничтожение связи (раздел 18А.5). 6. Выводимые атрибуты (раздел 18.4.6). Объекты обладают состоянием, поведением и индивидуальностью. Это отражается жизненным циклом объекта. Объекты создаются системой и должны ииициализироваться в правильном состоянии. В С++ имеются средства уничтожения объектов по желанию программиста, тогда как в Дача программист может лишь предложить сборщику мусора уничтожить объект. В обоих языках имеются специальные методы, которые запускаются в момент создания объекта, а также методы, позволяюшие описать завершение существования объекта.
Объекты могут запрашивать друг у друга сервисы и информацию. Для этого оии вызывают методы друг друга. В )ача и в С++ поведение объектов вызывается посредством оператора членства «.», который указывает необходимость вызова операнда, иаходяШегося в правой части (метода класса), для указанного целевого объекта. Тот же синтаксис используется для обрашеиия к атрибутам объекта: Ху означает атрибут у объекта Х. Обычно атрибуты иикапсулируются, а потому оказываются недоступны внешним объектам. 392 Глава 18 ° Объектно-ориентированные языки В контексте класса объектам доступна ссылка на самих себя, которая в обоих языках называется гйи.
Явно указывать эту ссылку перед именами членов класса не обязательно. В з ача/п() равносильно й)з/п0, а у= 10 означает гй)ху- 10. В С++ йЬ вЂ” это указатель, а потому с ним необходимо использовать специальный оператор членства ЙЬ->/пО. Чтобы объект мог обратиться к другому объекту за сервисами или информацией, он должен знать имя целевого объекта. Это имя может быть получено из связи: в составе объекта может присутствовать указатель или ссылка на другой объект или через параметр, когда объект получает идентификатор другого объекта при вызове метода. Любой вызов методов целевого объекта осуществляется через идентификатор и ограничивается установленным для этих методов уровнем доступа.
В С++ и )ача существует концепция статических (зййс) членов классов, которые используются всеми объектами класса совместно. Жизненный цикл статического элемента полностью отличается от жизненного цикла обычного объекта. К такому элементу можно обратиться через сам класс, независимо от существования экземпляров этого класса (см. раздел 18А.2). 18М.1. Создание обьекта В объектно-ориентированных языках объекты обычно создаются динамически (в процессе выполнения программы): программа запрашивает систему о создании экземпляра конкретного класса.
В )ауа это требование действует только на непримитивные типы, тогда как примитивные типы размещаются в памяти статически во время компиляции. В С++ допустимо статическое и динамическое выделение памяти и под примитивные, и под объектные типы. Для создания объектов в обоих языках используется оператор пев). ас++ // статическое выделение памяти пад один счет Ассоопо асст1) // статическое выделение памяти пол массив из 10 счетов Ассоцпс ассоцпсз1[10)) // динамическое выделение: определение указателя, // инициализация объекта оператором пен Ассоопп* асст2 = пен Ассоцпп) // динамическое создание массива из 10 счетов Ассоцпп* ассоцпоз2 = пен Ассоцпо(10)) //зава // создание ссылки, инициализация объекта оператором пеи Ассоцпс асса = пен Ассоцпс()) // создание массива из 10 ссылок, но не самих счетов Ассоопс ассоцпсз = пен Ассоцпс[10)) // создание счетов, на которые будут ссылатъся элементы массива Гол (1пс а=б) 1<10) хяя) ассоцпоз[1] = пен Ассоопс()) 18.4.
Реализация функциональности 393 Когда создается новый объект, система выделяет память под его атрибуты и выполняет другие действия, подразумеваемые началом жизненного цикла объекта. Объектно-ориентированные языки освобождают программиста от необходимости понимания технических деталей реализации объектов. ) ага и С++ позволяют программисту указывать, какие операции должны быть выполнены во время создания объекта, поэтому вы имеете возможность обеспечить внутреннюю непротиворечивость только что созданного объекта. Как только система завершает свои действия по созданию объекта, вызывается специальный метод этого объекта, называемый конструктором (сопзггцсгог). Конструктор — это метод, не возвращающий никакого значения. Его имя совпадает с именем класса.
Он может иметь произвольное количество параметров и может быть перегружен. Например, приведенный ниже код на )ача показывает, что класс Ассоипг (Счет) имеет два конструктора, один из которых требует указания начального баланса (а другой не принимает никаких аргументов). рсы1с с1ааа ассоспс ( рсЫьс )(ссоспс(11оас ореп1пээа1апсе) ( Ьа1апсе Ореп1пдэа1апсе; ) рсЬ|(с ассоопа() ( Ьа1апсе 0; ) Внутри конструктора можно присваивать значения членам класса, создавать входящие в него объекты и выполнять прочие действия. Конструктор выполняется уже для полностью сформированного объекта, поэтому он может вызывать другие методы и обладает теми же возможностями, привилегиями и ограничениями, как и все остальные методы. Если у объекта не определен конструктор, считается, что он имеет форму Хоо.
Хотя такой конструктор не выполняет никаких действий, он допускает выражения, содержащие операцию создания объекта, имеющую соответствующую форму. После создания параметризованного конструктора неявный конструктор без параметров больше не будет поддерживаться системой. Если он вам нужен, придется определить его самостоятельно (как это сделано в примере выше). Конструкторы в подклассах тоже не представляют особых сложностей для понимания. Объект, принадлежащий к типу подкласса, наследует атрибуты и методы суперкласса, а также содержит все члены, определенные на уровне подкласса.
Можно считать, что сначала создается родительский объект, а потом к нему добавляется часть, определенная в подклассе. Хотя конструкторы не наследуются, они выполняются последовательно от наиболее общих к наиболее конкретным. В случае С++, где допускается статическое создание объектов, объекты-члены создаются рекурсивно (с вызовом их конструкторов) до завершения создания содержащего их объекта. Только после этого запускается конструктор внешнего объекта. Рассмотрим это на примере: с1ааа Х ( рпЫас: Х() ( посс « "х!": ) 394 Глава 18 ° Объектно-ориентированные языки с1азз т : рцЬ11с Х ( рцЫьс: т () ( соцс « "т! )' с1азз 2: рцЫЕс т ( рцЬ11с: 2() ( сов< « Е!;) ): 1пс иа1п() ( 2 з( // просто создаем объект Е теецтп О; ) В результате выполнения этой программы будет выведена строка Х!У(Х!.
Отсутствие явно определенного конструктора считается плохим стилем программирования. По умолчанию С++ никак не инициализирует члены класса, тогда как)ауа инициализирует их значениями О или ли!! в зависимости от типа. В любом случае состояние объекта вряд ли будет корректным с точки зрения модели состояний. Назначение конструктора в том, чтобы программист имел возможность провести инициализацию объекта и операции над ним таким образом, что к началу своей деятельности этот объект был бы полностью сформированным, внутренне согласованным и готовым к работе.
Если над созданным объектом не должны быть выполнены никакие операции, )ача позволяет инициализировать элементы прямо в определении класса. В С++ для этого используется список инициализации членов, в котором указываются значения членов, присваиваемые им перед запуском конструктора. В обоих языках операции присваивания можно помещать в тело конструктора, однако инициализация всегда считается предпочтительнее присваивания. //дача рцЫ1с с1авз Ассоцпе ( рт1часе 21оас ьа1апсе = О; // инициализация рцЬ11с Иссоцпс() () // в конструкторе присваивание уже не нужно //с++ с1авз АссоцпС ( 21оас Ьа1апсе; // указывать значение нельзя рцЫ1с: Ассоцпп() : Ьа1апсе(О) () //список инициализации ) В С++ имеется также копирующий конструктор, имеющий семантику копирования при присваивании.
По умолчанию предоставляется конструктор формы Х(солзг Хсу х), подразумевающий почленное копирование содержимого. )ача не поощряет копирование объектов: программист должен указать, что класс реализует интерфейс С!Олеа!))е, и перекрыть метод с(опе0 класса ОЬ!есе 18.4. Реализация функциональности 395 18Я.2. Существование обьекта Статически выделенные объекты, созданные во время компиляции, которые в С++ могут иметь произвольный тип, а в )ача могут быть только примитивными типами и переменными-ссылками, существуют в рамках программного блока, ограниченного фигурными скобками О.
Они автоматически уничтожаются, когда точка выполнения выходит за границы этого блока. Динамически выделенные объекты хранятся в памяти до тех пор, пока они не будут уничтожены явно (в С++) или пока не перестанут использоваться программой (в )ата). В обоих языках допустимо определение статических членов класса. Такие члены принадлежат не какому-либо объекту класса, но всему классу в целом, причем работать с ними можно даже в отсутствие экземпляров класса (если, конечно, эти члены являются открытыми). Для этого служит синтаксис Хл5гаг1сМегйоИЦ или Х.5гаг(сМегйог(() (С++, )ача). Можно обращаться к ним и через объекты класса, но при этом нужно помнить о том, что они не являются членами данного экземпляра. Статические члены существуют до создания первого объекта данного типа— в момент создания программы С++ или при загрузке класса )ага — и не прекращают своего существования до завершения программы. В С++ статические члены существуют в виде независимых объектов (для них выделяется отдельная память), тогда как в )ага каждый класс сам по себе существует независимо (имеется экземпляр самого класса), и ему принадлежат все статические члены.
Жизненный цикл статических членов класса никак не связан с объектами этого класса. Поскольку статические методы не являются членами классов, синтаксис гИВ (и зирег) внутри них применять бессмысленно. Из статического метода можно сослаться на обычные данные, находящиеся внутри объекта, только указав имя этого объекта. В С++ глобально определенные переменные характеризуются таким же жизненным циклом, что и статические члены классов. Они создаются перед началом программы и удаляются при ее завершении. Глобальные переменные считаются примером плохого стиля программирования, однако глобальные функции используются в С++ достаточно широко.