[ <<< | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Источники | >>> ]
© 2001 А.И. Легалов
Объектно-ориентированное программирование предлагает следующие варианты композиции для создания агрегатов:
Следует также отметить, что разная терминология в ОО подходе усугубляется также различными способами организации классов. В языке программирования C++ тело обычной и виртуальной процедуры может располагаться как внутри оболочки, содержащей также переменные класса (внутреннее описание процедуры класса), так и вне нее. В последнем случае она представляет внешнее описание процедуры, которому должно предшествовать ее объявление в оболочке.
В языке программирования Java, а также в ряде других языков, процедура всегда располагается внутри оболочки. В ней же размещаются и переменные класса.
В языке программирования Оберон-2 виртуальная процедура класса всегда размещается вне физической оболочки, составляя, однако, со связанным типом данных единое целое, подчиняющееся законам полиморфизма и наследования. При этом сохраняется терминология присущая процедурному подходу. Такая относительность в целом ведет к одинаковому набору связей между объектами класса, но разным образом сказывается на их размещении в тексте программы. Это позволяет изменять связанную процедуру, не изменяя тип данных, к которому она привязана. Но изменения затрагивают модуль, в котором находятся АТД и связанные с ним процедуры. А так как типы данных и связанные процедуры должны находиться в одном модуле, то его можно считать общей физической оболочкой класса для всех размещаемых в нем АТД и связанных с ними процедур. В других же языках программирования изменения, связанные с модификацией данных или процедур класса, происходят внутри своей собственной оболочки. В целом же можно считать, что изменения в классе, как совокупности оболочки, переменных и процедур, происходят в любом случае.
Следует отметить, что процедуры класса осуществляют непосредственный доступ к его данным (через тела процедур), что ведет к фиксации используемого адресного пространства. Однако каждый из порождаемых экземпляров класса имеет дополнительно свою адресную привязку, относительно которой и располагаются адреса используемые в телах процедур. Создается иллюзия наличия для каждого экземпляра класса своего экземпляра внутренних процедур, хотя реальная реализация обеспечивает обслуживания всех экземпляров одним комплектом процедур [Голуб] через использование на системном уровне механизма параметризации доступа к членам класса. Независимо от трактовки данного способа доступа, он, по своим параметрам, эквивалентен доступу к телу процедуры через сигнатуру.
Контейнер для хранения различных геометрических фигур, реализованный с применением объектно-ориентированного подхода, содержит не только данные, но и процедуры их обработки. Описание, определяющее интерфейс класса container, доступный пользователям, выглядит следующим образом:
//---------------------------------------------------------------------- // Простейший контейнер на основе одномерного массива //---------------------------------------------------------------------- // Контейнер должен знать о фигуре #include "shape_atd.h" //---------------------------------------------------------------------- // Описание контейнера class container { enum {max_len = 100}; // максимальная длина int len; // текущая длина shape *cont[max_len]; public: void In(); // ввод фигур в контейнер из входного потока void Out(); // вывод фигур в выходного потока double Area(); // подсчет суммарной площади void Clear(); // очистка контейнера от фигур container(); // инициализация контейнера ~container() {Clear();} // утилизация контейнера перед уничтожением }; //---------------------------------------------------------------------- |
Как и в случае с процедурной программой, интерфейс с внешним миром осуществляется через аналогичные же процедуры, но уже являющиеся методами класса:
Большинство методов класса отличаются от независимых процедур только отсутствием в сигнатуре входного параметра, обеспечивающего доступ к данным в процедурном подходе. Однако дополнительные языковые возможности C++ позволяют более гибко реализовать инициализацию и утилизацию с применением конструктора и деструктора, что позволяет убрать дополнительные вызовы процедур в самой программе.
При разработке больших программных проектов, содержащих объемные процедуры, тела процедур - членов класса, обычно размещаются (если язык предоставляет такую возможность) в других единицах компиляции. Несмотря на то, что наш проект мал, да и тела процедур ростом не вышли, будем использовать этот же принцип. Это позволит в дальнейшем более гибко имитировать эволюционное развитие программы. Реализация процедур контейнера выполнена следующим образом:
//---------------------------------------------------------------------- // Необходимо знать описание контейнера и методов фигуры, // доступных через container_atd.h #include "container_atd.h" //---------------------------------------------------------------------- // Прототип обычной внешней функции, формирующей фигуру при вводе shape *In(); //---------------------------------------------------------------------- // Инициализация контейнера container::container(): len(0) { } //---------------------------------------------------------------------- // Очистка контейнера от элементов (освобождение памяти) void container::Clear() { for(int i = 0; i < len; i++) { delete cont[i]; } len = 0; } //---------------------------------------------------------------------- // Ввод содержимого контейнера void container::In() { cout << "Do you want to input next shape" " (yes=\'y\', no=other character)? " << endl; char k; cin >> k; while(k == 'y') { cout << len << ": "; if((cont[len] = simple_shapes::In()) != 0) { len++; } cout << "Do you want to input next shape" " (yes=\'y\', no=other character)? " << endl; cin >> k; } } //---------------------------------------------------------------------- // Вывод содержимого контейнера void container::Out() { cout << "Container contents " << len << " elements." << endl; for(int i = 0; i < len; i++) { cout << i << ": "; cont[i]->Out(); } } //---------------------------------------------------------------------- // Вычисление суммарной площади для фигур, размещенных в контейнере double container::Area() { double a = 0; for(int i = 0; i < len; i++) { a += cont[i]->Area(); } return a; } //---------------------------------------------------------------------- |
Указанные функции использованы в примере, расположенном в архиве oop_examp1.zip.
[ <<< | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Источники | >>> ]