Курс ООП в С презентация. ООП в с++(полный курс). Объекты и классы
Скачать 1.76 Mb.
|
Методы классовНам же остается только создать объект-группу и применить к нему эти функции любым удобным способом: void main() { group G; //создаем объект-группу из объектов типа person G.for_each(set_name); //определяем для них имена cout << "Names:" << endl; FP pf = show_name; //создаем указатель на функцию вывода G.for_each(pf); //применяем этот указатель к группе } Свободные подпрограммы часто возникают во время анализа и проектирования на границе объектно-ориентированной системы и ее процедурного интерфейса с внешним миром. Методы классовУтилиты классов употребляются одним из двух способов. Во-первых, утилиты класса могут содержать одну или несколько свободных подпрограмм, и тогда следует просто перечислить логические группы (библиотеки) таких функций - нечленов. Во-вторых, утилита класса может обозначать класс, имеющий только переменные (и операции) класса (в C++ это означало бы класс только со статическими элементами). class util { public: static void show_name(person& argname); static void set_name(person& argname); }; В этом случае обращение к методу такого класса при отсутствии экземпляров у последнего должно осуществляться через оператор обращения к области видимости: FP pf = util::show_name; Связь классов с утилитой может быть отношением использования, но не наследования или агрегирования. В свою очередь, утилита класса может вступать в отношение использования с другими классами и содержать их статические экземпляры, но не может от них наследовать. Статические компоненты класса Спецификатор static описывает статические атрибуты и методы класса, которые можно рассматривать как глобальные переменные и функции, доступные в пределах класса. Статические атрибуты применяются для хранения данных, общих для всех объектов класса, например, количества объектов или ссылки на разделяемый всеми объектами ресурс. Эти атрибуты существуют для всех объектов класса в единственном экземпляре, то есть не дублируются. Особенности статических атрибутов:
Статические атрибуты доступны как через имя класса, так и через имя объекта. Рассмотрим работу со статическими элементами класса в новой реализации контейнера group, пополняемого экземплярами класса person. Чтобы организовать такую динамическую структуру данных, каждый новый объект этого класса должен знать адрес созданного ранее объекта, который значение которого хранит статический атрибут last. Метод add() и метод-итератор for_each() объявлены статическими, поскольку производимые ими действия будут относиться к единственной динамической структуре класса group. class group { public: person* Person; group(); static void add(person&); static void group::for_each(void (*)(person&)); private: int number; group* next; static group* last; }; Прежде чем использовать статический атрибут, надо присвоить ему начальное значение (что следует делать в .cpp файле реализации класса, а не где-то ещё): group* group::last = 0; На статические атрибуты распространяется действие спецификаторов доступа, поэтому статические поля, описанные как private, нельзя изменить с помощью операции доступа к области действия. Это делается с помощью статических методов. Эти методы могут обращаться непосредственно только к статическим атрибутам и вызывать только другие статические методы класса, потому что им не передается скрытый указатель this. Указатель this хранит адрес того объекта, который вызвал функцию и неявно используется внутри метода для ссылок на элементы объекта. В явном виде этот указатель применяется в основном для возвращения из метода указателя (return this;) или ссылки (return *this;) на вызванный объект. group::group() { number = 0; next = last; last = this; } void group::add(person& p) { static int z = 0; group* x = new group; x->Person = &p; z++; x->number = z; } void group::for_each(void (*fp)(person&)) { group* pz = last; while (pz) { fp(*(pz->Person)); pz = pz->next; } } Обращение к статическим методам производится так же, как к статическим атрибутам, – через имя класса: void main() { person A, B, C; A.set_name("Gogi"); B.set_name("Gagik"); C.set_name("Ara"); group::add(A); group::add(B); group::add(C); group::for_each(show_name); } … либо, если создан хотя бы один объект класса, через имя объекта. Дружественные функции и классы Иногда скрытые атрибуты класса требуется открыть для ограниченного доступа извне, что достигается использованием дружественных функций и дружественных классов. Дружественные функции применяются для доступа к скрытым атрибутам класса и представляют собой альтернативу методам. Методы, как правило, связаны с атрибутами объекта. Правила описания и особенности дружественных функций:
Дружественная функция может быть обычной функцией или методом другого ранее определенного класса. На нее не распространяется действие спецификаторов доступа, место размещения ее объявления в классе безразлично. Одна функция может быть дружественной сразу нескольким классам. Допустим, мы хотим ограничить возможности по изменению состояния некоторых объектов предметной области таким образом, чтобы делать это могла только специальная функция. Это может делаться исходя из того, что реализация последней должна соответствовать определенному набору требований разработчика по организации взаимодействия между пользователем и объектами бизнеслогики системы. Такой подход может быть актуальным, когда предполагается возможность создания новой надстройки к базовой архитектуре объектов системы и стоит задача защититься от некорректных изменений объектов предметной области, которые новый модуль предполагает получать из общей базы данных. С этой целью мы можем объявить методы-модификаторы класса person как закрытые (или защищенные, если в будущем предполагается наследование), а необходимую для обеспечения интерфейса с пользователем функцию set_name() как дружественную: class person { friend void set_name(person& argname); private: //... } Если все методы какого-либо класса должны иметь доступ к скрытым атрибутам другого, весь класс объявляется дружественным с помощью ключевого слова friend. Так, мы можем объявить класс dialog в качестве дружественного для person, если хотим обеспечить изменение внутреннего состояния объектов этого класса средствами спроектированного диалога. class person { friend class dialog; //... } Естественно, перечень друзей не должен ограничиваться одним классом или функцией, а определяется лишь соображениями разумной достаточности. Использования дружественных функций нужно по возможности избегать, поскольку они нарушают принцип инкапсуляции и, таким образом, затрудняют отладку и модификацию программы. Перегрузка операций |