friend
(C++)
В некоторых случаях класс полезен для предоставления доступа на уровне члена к функциям, которые не являются членами класса, или всем членам в отдельном классе. Эти бесплатные функции и классы называются друзьями, отмеченными friend
ключевое слово. Только реализатор класса может объявить, что является для него дружественным элементом. Функция или класс не может объявить себя другом любого класса. В определении класса используйте friend
ключевое слово и имя немемберной функции или другого класса, чтобы предоставить ему доступ к частным и защищенным членам класса. В определении шаблона параметр типа может быть объявлен как .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 как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по