|
Программирование >> Поддержка объектно-ориентированного программирования
применение определяемых пользователем функций размещения в свободной памяти и функций освобождения памяти. 5.2 Классы и члены Класс - это пользовательский тип. Этот раздел знакомит с основными средствами определения класса, создания его объектов, работы с такими объектами и, наконец, удаления этих объектов после использования. 5.2.1 Функции-члены Посмотрим, как можно представить в языке понятие даты, используя для этого тип структуры и набор функций, работающих с переменными этого типа: struct date { int month, day, year; }; date today; void set date(date*, int, int, int); void next date(date*); void print date(const date*); ... Никакой явной связи между функциями и структурой date нет. Ее можно установить, если описать функции как члены структуры: struct date { int month, day, year; void set(int, int, int); void get(int*, int* int*); void next(); void print(); Описанные таким образом функции называются функциями-членами. Их можно вызывать только через переменные соответствующего типа, используя стандартную запись обращения к члену структуры: date today; date my birthday; void f() my birthday.set(3 0,12,1950); today.set(18,1,1991); my birthday.print(); today.nextO; Поскольку разные структуры могут иметь функции-члены с одинаковыми именами, при определении функции-члена нужно указывать имя структуры: void date::next() if (++day > 28 ) { здесь сложный вариант В теле функции-члена имена членов можно использовать без указания имени объекта. В таком случае имя относится к члену того объекта, для которого была вызвана функция. 5.2.2 Классы Мы определили несколько функций для работы со структурой date, но из ее описания не следует, что это единственные функции, которые предоставляют доступ к объектам типа date. Можно установить такое ограничение, описав класс вместо структуры: class date { int month, day, year; public: void set(int, int, int); void get(int*, int*, int*); void next(); void print() Служебное слово public (общий) разбивает описание класса на две части. Имена, описанные в первой частной (private) части класса, могут использоваться только в функциях-членах. Вторая - общая часть -представляет собой интерфейс с объектами класса. Поэтому структура - это такой класс, в котором по определению все члены являются общими. Функции-члены класса определяются и используются точно так же, как было показано в предыдущем разделе: void date::print() печать даты в принятом в США виде cout << month << / << day << / << year ; Однако от функций не членов частные члены класса date уже ограждены: void backdate() today.day--; ошибка Есть ряд преимуществ в том, что доступ к структуре данных ограничен явно указанным списком функций. Любая ошибка в дате (например, December, 36, 1985) могла быть внесена только функцией-членом, поэтому первая стадия отладки - локализация ошибки - происходит даже до первого пуска программы. Это только частный случай общего правила: любое изменение в поведении типа date может и должно вызываться изменениями в его членах. Другое преимущество в том, что потенциальному пользователю класса для работы с ним достаточно знать только определения функций-членов. Защита частных данных основывается только на ограничении использования имен членов класса. Поэтому ее можно обойти с помощью манипуляций с адресами или явных преобразований типа, но это уже можно считать мошенничеством. 5.2.3 Ссылка на себя В функции-члене можно непосредственно использовать имена членов того объекта, для которого она была вызвана: class X { int m; public: int readm() { return m; } void f(X aa, X bb) int a = aa.readmO; int b = bb.readmO; ... При первом вызове readm() m обозначает aa.m, а при втором - bb.m. У функции-члена есть дополнительный скрытый параметр, являющийся указателем на объект, для которого вызывалась функция. Можно явно использовать этот скрытый параметр под именем this. Считается, что в каждой функции-члене класса X указатель this описан неявно как X *const this; и инициализируется, чтобы указывать на объект, для которого функция-член вызывалась. Этот указатель нельзя изменять, поскольку он постоянный (*const). Явно описать его тоже нельзя, т.к. this -это служебное слово. Можно дать эквивалентное описание класса X: class X { int m; public: int readm() { return this->m; } Для обращения к членам использовать this излишне. В основном this используется в функциях-членах, непосредственно работающих с указателями. Типичный пример - функция, которая вставляет элемент в список с двойной связью: class dlink { dlink* pre; указатель на предыдущий элемент dlink* suc; указатель на следующий элемент public: void append(dlink*); ... void dlink::append(dlink* p) p->suc = suc; т.е. p->suc = this->suc p- >pre = this; явное использование this suc->pre = p; т.е. this->suc->pre = p suc = p; т.е. this->suc = p dlink* list head; void f(dlink* a, dlink* b) ... list head->append(a); list head->append(b); Списки с такой общей структурой служат фундаментом списочных классов, описываемых в главе 8. Чтобы присоединить звено к списку, нужно изменить объекты, на которые настроены указатели this, pre и suc. Все они имеют тип dlink, поэтому функция-член dlink::append() имеет к ним доступ. Защищаемой единицей в С++ является класс, а не отдельный объект класса. Можно описать функцию-член таким образом, что объект, для которого она вызывается, будет доступен ей только по чтению. Тот факт, что функция не будет изменять объект, для которого она вызывается (т.е. this*), обозначается служебным словом const в конце списка параметров: class X { int m; public: readme() const { return m; } writeme(int i) { m = i; } Функцию-член со спецификацией const можно вызывать для постоянных объектов, а функцию-член без такой спецификации - нельзя: void f(X& mutable, const X& constant) mutable.readmeO; нормально mutable.writeme(7); нормально constant.readmeO; нормально constant.writeme(7); ошибка
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |