
- •1. Дополнения к с
- •1.1. Комментарии
- •1.2. Ключевые слова
- •1.3. Константы
- •1.4. Блочные объявления
- •1.5. Ссылки
- •1.6. Новая роль имён перечислений, структур и объединений
- •1.7. Распределение памяти
- •1.8. Встраиваемые функции
- •1.9. Перегрузка функций
- •1.10. Задание для параметров функции значений по умолчанию
- •1.11. Дополнительные операции для доступа к данным
- •1.12. Предопределённые потоки ввода-вывода
- •2.1. Инкапсуляция
- •2.2. Разграничение доступа (скрытие данных и методов)
- •2.3. Друзья классов
- •2.4. Конструкторы и деструкторы
- •2.5. Конструктор по умолчанию
- •2.6. Конструктор копирования
- •2.7. Несколько слов о деструкторах
- •2.8. Перегрузка операций
- •3.1. Наследование
- •3.2. Виртуальные функции –полиморфизм
- •3.3. Шаблоны
2.3. Друзья классов
Иногда ограничение на доступ к частным и защищенным компонентам класса только посредством методов класса оказывается неоправданно жестким. Бывают случаи, когда необходимо разрешить такой доступ.
В языке С++ предусмотрена возможность обеспечить доступ к частным и защищенным компонентам извне класса при помощи ключевого слова friend, которое говорит о том, что следующая за ним функция является «другом» данного класса и имеет полный доступ ко всем его компонентам, не являясь в то же время методом этого класса. Такие дружественные функции не зависят от положения в классе и спецификаторов доступа и ничем другим от обычных не отличаются.
class MyClass
{
private:
int nVar;
friend void friendFunc (MyClass &clArg, int narg); // Дружественная
// функция public: void memberFunc (int nArg); // Метод класса
// Определения функций
void friend friendFunc (MyClass &clArg,int nArg)
{clArg.nVar = nArg;}
void memberFunc (int nArg) {nVar = nArg;}
. . .
// Создаём объект класса
MyClass clObj;
// Обращаемся к частному компоненту класса
friendFunc(clObj,7);
memberFunc(7);
Дружественные функции класса дают программисту сбалансированный подход к принципу инкапсуляции данных: если методы доступа влекут за собой слишком большие дополнительные издержки, то иногда проще дать некоторой внешней функции права непосредственного доступа к компонентам класса. Более того, одна и та же функция может быть дружественной для нескольких классов,
В качестве дружественной функции может выступать и некоторый метод другого класса:
class Myclass1
{
. . .
// Метод memberfuncMyclass2 класса Myclass2 объявляется дружественным
// классу MyClass1
friend void MyClass2 :: memberFuncMyClass2(. . .);
. . .
};
По аналогии с функциями и методами можно объявить дружественным весь класс. При этом все методы такого дружественного класса смогут обращаться ко всем компонентам класса:
class Myclass {
{
. . .
// Класс MyFriend объявляется дружественным классу MyClass
friend class MyFriend;
. . .
};
И ещё два замечания:
«Дружба» классов не транзитивна. Другими словами, если класс MyClass1 – друг класса MyClass2, а MyClass2 – друг MyClass3, то это не означает, что MyClass1 – друг MyClass3. Однако «дружба» наследуется, но об этом – более подробно после знакомства с наследованием.
«Дружба» классов – не симметрична, т. е. если класс MyFriend объявлен другом MyClass, то это не означает, что MyClass имеет доступ к частным и защищенным компонентам класса MyFriend. Таким образом, права для доступа к классу может предоставить только автор класса, а не программист, написавший функцию или некоторый другой класс.
Пойдём дальше. Как правило, перед использованием объект должен быть инициализирован. В языке С этот процесс выполнялся либо автоматически (для глобальных и статических элементов), либо путем определения специальной функции, которая вызывается сразу после создания объекта, до его использования. Аналогичный подход можно использовать и в С++. Однако в нём предусмотрен способ лучше.