Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
OOP.doc
Скачиваний:
13
Добавлен:
25.04.2019
Размер:
1.34 Mб
Скачать

3. Дружественные функции и классы

3.1. Дружественные функции

Кроме спецификаторов доступности public, private, protected и ключей класса? доступностью компонент класса можно управлять через механизм дружественных функций и классов. Под дружественной функцией (friend) класса понимается функция, которая, не являясь компонентом этого класса, имеет доступ ко всем его компонентам, включая защищенные и закрытые. В свою очередь, указанный класс принято называть классом, предоставляющим «дружбу» (befriended class).

Чтобы сделать функцию дружественной, надо включить ее заголовок с предшествующим ему ключевым словом friend в требуемый класс. В остальном дружественная функция – это обычная функция. Она может быть компонентом другого класса или глобальной функцией, а также определяться в каком-либо пространстве имен. Дружественная функция не является компонентом класса, к которому объявлена дружественной, и поэтому при работе с объектами этого класса не получает указателя this. Соответственно, для ее вызова нельзя применять ни операцию «.», ни операцию «–>» (исключение составляет лишь случай, когда дружественная функция – компонент другого класса), а чтобы обеспечить работу функции с объектами класса, их нужно передавать в нее через механизм параметров. На дружественную функцию не действуют спецификаторы доступности public, protected и private; следовательно, и размещение ее прототипа в классе, предоставляющем «дружбу», безразлично. Если же дружественная функция входит в качестве компонентной в другой класс, на нее действуют все ограничения ее собственного класса. Функция может быть дружественной по отношению сразу к нескольким независимым или взаимосвязанным классам.

В рассмотренном ниже примере используется глобальная дружественная функция.

Пример

class CBefriended { // класс, предоставляющий «дружбу»

int i;

// объявление дружественной функции

friend void friend_func(CBefriended *, int);

public:

void member_func(int); // компонентная функция

};

/* внешние определения */

// операция :: не нужна, так как friend_func не входит в CBefriended

void friend_func(CBefriended * ptr, int a) {

// доступ к объекту CBefriended выполняется через указатель ptr

ptr–>i = a;

}

void CBefriended::member_func(int a) { // компонентная функция

this->i = a;

}

/* вызовы */

void another_func() {

CBefriended befriended;

friend_func( &befriended, 6 ); // вызов дружественной функции

befriended.member_func(6); // вызов компонентной функции

}

Ниже дан пример с дружественной компонентной функцией.

Пример

class CBefriended; // класс, предоставляющий «дружбу»

class CFriendHolder { // класс, содержащий дружественную функцию

public:

int friend_member_func(CBefriended * p);

// без предварительного объявления CBefriended не компилируется

};

class CBefriended { // класс, предоставляющий «дружбу»

int i;

// декларация дружественной функции

friend int CFriendHolder::friend_member_func(CBefriended * p);

};

// внешнее определение дружественной функции

int CFriendHolder::friend_member_func(CBefriended * p) { return p->i; }

...

void another_func() {

CBefriended befriended;

CFriendHolder friend_holder;

// вызов дружественной компонентной функции

int i = friend_holder.friend_member_func( &befriended );

...

}

Аналогичным образом можно сделать одну и ту же функцию дружественной сразу по отношению к нескольким независимым классам. Возможно введение дружественных функций и к классам, связанным иерархией наследования. Однако функцию необходимо отдельно объявлять дружественной по отношению к каждому классу: дружественность не передается при наследовании. Например, функция f дружественна к классу C, а у класса C есть открытый производный класс D. В этом случае функция f не будет другом к классу D без явного объявления. Если функция имеет несколько вариантов перегрузки, то объявление одного из них дружественным к какому-либо классу не делает автоматически таковыми другие варианты. И еще одна тонкость. Дружественную функцию иногда можно сразу определить в классе, предоставляющем дружбу. Это возможно при условии, что класс не локальный, а функция не является компонентом другого класса и представлена неквалифицированным именем. Определенная таким образом функция будет inline-функцией и лексически будет принадлежать сфере действия имен класса, дающего «дружбу».

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]