friend
(C++)
В некоторых случаях класс полезен для предоставления доступа на уровне члена к функциям, которые не являются членами класса, или всем членам в отдельном классе. Эти бесплатные функции и классы называются друзьями, помеченными ключевым словом friend
. Только реализатор класса может объявить, что является для него дружественным элементом. Функция или класс не может объявить себя другом любого класса. В определении класса используйте friend
ключевое слово и имя функции nonmember или другого класса, чтобы предоставить ему доступ к частным и защищенным членам класса. В определении шаблона параметр типа может быть объявлен как .friend
Синтаксис
friend-declaration
:
friend
function-declaration
friend
function-definition
friend
elaborated-type-specifier
;
;
friend
simple-type-specifier
;
friend
typename-specifier
;
friend
Объявления
Если вы объявляете friend
функцию, которая не была объявлена ранее, эта функция экспортируется в заключающую область неклассов.
Функции, объявленные в friend
объявлении, рассматриваются как если бы они были объявлены с помощью ключевого extern
слова. Дополнительные сведения см. в разделе extern
.
Хотя функции с глобальной областью можно объявить как friend
функции до их прототипов, функции-члены не могут быть объявлены как friend
функции до появления их полного объявления класса. В следующем коде показано, как такое объявление завершается ошибкой:
class ForwardDeclared; // Class name is known.
class HasFriends
{
friend int ForwardDeclared::IsAFriend(); // C2039 error expected
};
В предыдущем примере имя ForwardDeclared
класса вводится в область действия, но полное объявление (в частности, часть, объявляющая функцию IsAFriend
) не известна. friend
Объявление в классе HasFriends
создает ошибку.
В C++11 существует две формы объявлений друзей для класса:
friend class F;
friend F;
Первая форма представляет новый класс F, если существующий класс по имени не найден в самом внутреннем пространстве имен. C++11: вторая форма не вводит новый класс; его можно использовать, когда класс уже объявлен, и его необходимо использовать при объявлении параметра типа шаблона или typedef
в качестве friend
.
Используйте friend class F
, когда указанный тип еще не объявлен:
namespace NS
{
class M
{
friend class F; // Introduces F but doesn't define it
};
}
Ошибка возникает, если вы используете friend
с типом класса, который не был объявлен:
namespace NS
{
class M
{
friend F; // error C2433: 'NS::F': 'friend' not permitted on data declarations
};
}
В следующем примере friend F
относится к F
классу, объявленному за пределами области NS.
class F {};
namespace NS
{
class M
{
friend F; // OK
};
}
Используется friend F
для объявления параметра шаблона в качестве друга:
template <typename T>
class my_class
{
friend T;
//...
};
Используется friend F
для объявления типа в качестве друга:
class Foo {};
typedef Foo F;
class G
{
friend F; // OK
friend class F // Error C2371 -- redefinition
};
Чтобы объявить два класса как дружественные друг другу, весь второй класс должен быть указан как дружественный для первого класса. Причина такого ограничения заключается в том, что компилятор получает достаточные сведения для объявления отдельных дружественных функций только в момент объявления второго класса.
Примечание.
Хотя весь второй класс должен быть дружественным для первого класса, можно выбрать, какие функции первого класса будут дружественными для второго класса.
дружественные функции
friend
Функция — это функция, которая не является членом класса, но имеет доступ к частным и защищенным элементам класса. Другие функции не считаются членами класса; они являются обычными внешними функциями, которым предоставляются специальные привилегии доступа. Друзья не входят в область действия класса, и они не вызываются с помощью операторов выбора членов (и ->), если они не являются членами другого класса. Функция friend
объявляется классом, предоставляющим доступ. Объявление friend
можно поместить в любое место в объявлении класса. Это не влияет на ключевые слова управления доступом.
В следующем примере показан класс Point
и дружественная функция ChangePrivate
. Функция friend
имеет доступ к члену частных данных объекта, который Point
он получает в качестве параметра.
// friend_functions.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
class Point
{
friend void ChangePrivate( Point & );
public:
Point( void ) : m_i(0) {}
void PrintPrivate( void ){cout << m_i << endl; }
private:
int m_i;
};
void ChangePrivate ( Point &i ) { i.m_i++; }
int main()
{
Point sPoint;
sPoint.PrintPrivate();
ChangePrivate(sPoint);
sPoint.PrintPrivate();
// Output: 0
1
}
Члены класса как дружественные элементы
Функции-члены класса могут быть объявлены в других классах как дружественные. Рассмотрим следующий пример:
// classes_as_friends1.cpp
// compile with: /c
class B;
class A {
public:
int Func1( B& b );
private:
int Func2( B& b );
};
class B {
private:
int _b;
// A::Func1 is a friend function to class B
// so A::Func1 has access to all members of B
friend int A::Func1( B& );
};
int A::Func1( B& b ) { return b._b; } // OK
int A::Func2( B& b ) { return b._b; } // C2248
В предыдущем примере доступ к классу B
предоставляется friend
только функцияA::Func1( B& )
. Поэтому доступ к частному члену _b
является правильным в Func1
классе A
, но не в Func2
.
Класс friend
— это класс, все функции-члены которого являются friend
функциями класса, т. е. функции-члены которых имеют доступ к частным и защищенным членам другого класса. Предположим, что в классе friend
было следующее объявление B
:
friend class A;
В этом случае все функции-члены в классе A
получили friend
бы доступ к классу B
. Следующий код является примером friend
класса:
// classes_as_friends2.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
class YourClass {
friend class YourOtherClass; // Declare a friend class
public:
YourClass() : topSecret(0){}
void printMember() { cout << topSecret << endl; }
private:
int topSecret;
};
class YourOtherClass {
public:
void change( YourClass& yc, int x ){yc.topSecret = x;}
};
int main() {
YourClass yc1;
YourOtherClass yoc1;
yc1.printMember();
yoc1.change( yc1, 5 );
yc1.printMember();
}
Дружба не является взаимной, если только явно не указано как таковое. В приведенном выше примере функции-члены YourClass
не могут получить доступ к частным членам YourOtherClass
.
Управляемый тип (в C++/CLI) не может иметь функций friend
, friend
классов или friend
интерфейсов.
Дружба не наследуется, то есть классы, производные от YourOtherClass
частных членов, не могут получить доступ YourClass
к частным членам. Дружба не является транзитивной, поэтому классы, которые являются друзьями YourOtherClass
не могут получить доступ к YourClass
частным членам.
На следующем рисунке показаны объявления 4 классов: Base
, Derived
, aFriend
и anotherFriend
. Только класс aFriend
имеет прямой доступ к закрытым членам класса Base
(и к любым возможным унаследованным членам класса Base
).
На схеме показано, что класс anotherFriend не имеет отношения друг с базой классов, которую друзья класс aFriend. Класс aFriend друг от класса Base, но у него нет отношения друг с классом Производное, даже если класс Производно наследует от Base. Это показывает, что наследование не означает, что производный класс имеет те же друзья, что и базовый класс.
Встроенные friend
определения
Пользовательские функции можно определить (в соответствии с телом функции) внутри объявлений классов. Эти функции являются встроенными функциями. Как и встроенные функции-члены, они ведут себя так, как будто они были определены сразу после того, как все члены класса были замечены, но до закрытия области класса (в конце объявления класса). Понятные функции, определенные внутри объявлений классов, находятся в области включаемого класса.
См. также
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по