Страница 4 из 25 Разграничение доступа к данным
Рассмотрим фрагмент старого С (*3), представляющий реализацию концепции даты: struct date { int day, month, year;}; struct date today; extern void set_date (); extern void next_date (); extern void next_today (); extern void print_date (); В приведенном примере нет явной связи между функциями и типом данных, нет и указаний на то, что данные функции должны быть единственными, которые имеют доступ к членам структуры d a t e . Необходимо же иметь возможность это указать. ____________ (*1) - В оригинале - "friends"ма frienфа functions - прим.переводчика. (*2) - В оригинале - deriveфа class, что можно перевести как "порождаемый". - прим.переводчика. (*3) - Ключевое слово void определяет функцию, не возвращающую значения. Оно было введено в С примерно в 1980 г. Простой путь сделать это заключается в объявлении типа данных, с которым может манипулировать только специфическое множество функций. Например: date my_birthday, today; set_date (&my_birthday, 30, 12, 1950); set_date (&today, 23, 6, 1983); print_date (&today); next_date (&today); Дружественные функции определяются обычным образом. Например : void next_date (date* d) { if <++d-> /* особый случай */ } } Такое решение проблемы упрятывания информации просто и часто достаточно эффективно. Оно не вполне гибко поскольку допускает доступ всем дружественным функциям к всем переменным типа Например, невозможно иметь различный набор дружественных функций для данных m y _ b i r t h d a y . Функция однако может быть дружественной более чем одному классу. Важность этого будет продемонстрирована в секции 19. Нет требования, чтобы дружественная функция могла манипулировать только переменнымим, передаваемыми как аргументы. Напримерм, в функцию может быть встроено имя глобальной переменной: void next_today () { if <++today.day> /* особый случай */ } } Защита данных от функций, не являющихся дружественными, основана на ограничении использования имен членов класса. Поэтому она может быть обойдена путем адресной манипуляции и явного преобразования типов. Можно получить несколько преимуществ от предоставления доступа к данным структуры только явно указанному списку функций. Любая ошибка, вызывающая недопустимое состояние переменной типа d a t e , должна быть вызвана кодом дружественной функции поэтому первый шаг отладки - локализация - будет завершен еще до того как программа будет исполнена. Это особый случай общей идеи, что любое изменение поведения типа d a t e может и должно быть вызвано изменениями в его дружественных функциях. Другое преимущество состоит в том, что потенциальному пользователю для того, чтобы научиться пользоваться таким типом нужно изучить только описания дружественных функций. Опыт С++ вполне это подтверждает. |