Namespaces
Variants
Views
Actions

Difference between revisions of "cpp/language/friend"

From cppreference.com
< cpp‎ | language
m (See Also: s/A/a, langlinks)
m (+Keywords)
 
(24 intermediate revisions by 5 users not shown)
Line 1: Line 1:
{{title|friend declaration}}
+
{{title|Friend declaration}}
 
{{cpp/language/classes/navbar}}
 
{{cpp/language/classes/navbar}}
 
The friend declaration appears in a {{rlp|class|class body}} and grants a function or another class access to private and protected members of the class where the friend declaration appears.
 
The friend declaration appears in a {{rlp|class|class body}} and grants a function or another class access to private and protected members of the class where the friend declaration appears.
Line 5: Line 5:
 
===Syntax===
 
===Syntax===
 
{{sdsc begin}}
 
{{sdsc begin}}
{{sdsc|num=1| {{c|friend}} {{spar|function-declaration}} }}
+
{{sdsc|num=1|{{ttb|friend}} {{spar|function-declaration}}}}
{{sdsc|num=2| {{c|friend}} {{spar|function-definition}} }}
+
{{sdsc|num=2|{{ttb|friend}} {{spar|function-definition}}}}
{{sdsc|num=3| {{c|friend}} {{spar|elaborated-class-specifier}} {{ttb|;}}}}
+
{{sdsc|num=3|notes={{mark until c++26}}|{{ttb|friend}} {{spar|elaborated-type-specifier}} {{ttb|;}}}}
{{sdsc|num=4|notes={{mark since c++11}}|
+
{{sdsc|num=4|notes={{mark since c++11}}<br>{{mark until c++26}}|
{{c|friend}} {{spar|simple-type-specifier}} {{ttb|;}}
+
{{ttb|friend}} {{spar|simple-type-specifier}} {{ttb|;}}
{{c|friend}} {{spar|typename-specifier}} {{ttb|;}}
+
{{ttb|friend}} {{spar|typename-specifier}} {{ttb|;}}
 
}}
 
}}
 +
{{sdsc|num=5|notes={{mark since c++26}}|{{ttb|friend}} {{spar|friend-type-specifier-list}} {{ttb|;}}}}
 
{{sdsc end}}
 
{{sdsc end}}
 +
 +
@1,2@ A function friend declaration.
 +
 +
@3-5@ A class friend declaration.
 +
 +
{{par begin}}
 +
{{par|{{spar|function-declaration}}|a {{rlp|function|function declaration}}}}
 +
{{par|{{spar|function-definition}}|a {{rlpsd|function#Function definition}}}}
 +
{{par|{{spar|elaborated-type-specifier}}|an {{rlp|elaborated type specifier}}}}
 +
{{par|{{spar|simple-type-specifier}}|a {{rlp|declarations#Specifiers|simple type specifier}}}}
 +
{{par|{{spar|typename-specifier}}|the keyword {{c/core|typename}} followed by a qualified identifier or qualified {{rlp|templates#Template identifiers|simple template identifier}}}}
 +
{{par|{{spar|friend-type-specifier-list}}|a non-empty comma-separated list of {{spar|simple-type-specifier}}, {{spar|elaborated-type-specifier}}, and {{spar sep|typename-specifier}}s, each specifier can be followed by an ellipsis ({{tt|...}})}}
 +
{{par end}}
  
 
===Description===
 
===Description===
@1@ Designates a function or several functions as friends of this class
+
@1@ Designates a function or several functions as friends of this class:
 
{{source|
 
{{source|
class Y {
+
class Y
 +
{
 
     int data; // private member
 
     int data; // private member
 +
   
 
     // the non-member function operator<< will have access to Y's private members
 
     // the non-member function operator<< will have access to Y's private members
 
     friend std::ostream& operator<<(std::ostream& out, const Y& o);
 
     friend std::ostream& operator<<(std::ostream& out, const Y& o);
Line 24: Line 40:
 
     friend X::X(char), X::~X(); // constructors and destructors can be friends
 
     friend X::X(char), X::~X(); // constructors and destructors can be friends
 
};
 
};
 +
 
// friend declaration does not declare a member function
 
// friend declaration does not declare a member function
 
// this operator<< still needs to be defined, as a non-member
 
// this operator<< still needs to be defined, as a non-member
Line 31: Line 48:
 
}
 
}
 
}}
 
}}
@2@ (only allowed in non-{{rlp|class#Local_classes|local}} class definitions) Defines a non-member function, and makes it a friend of this class at the same time. Such non-member function is always {{rlp|inline}}.
+
 
{{source|1=class X {
+
@2@ (only allowed in non-{{rlp|class#Local classes|local}} class definitions) Defines a non-member function, and makes it a friend of this class at the same time. Such non-member function is always {{rlp|inline}}{{rev inl|since=c++20|, unless it is attached to a {{rlp|modules|named module}}}}.
 +
{{source|1=
 +
class X
 +
{
 
     int a;
 
     int a;
     friend void friend_set(X& p, int i) {
+
   
 +
     friend void friend_set(X& p, int i)
 +
    {
 
         p.a = i; // this is a non-member function
 
         p.a = i; // this is a non-member function
 
     }
 
     }
public:
+
public:
     void member_set(int i) {
+
     void member_set(int i)
 +
    {
 
         a = i; // this is a member function
 
         a = i; // this is a member function
 
     }
 
     }
 
};
 
};
 
}}
 
}}
@3@ Designates the class, struct, or union named by the {{spar|elaborated-class-specifier}} (see {{rlp|elaborated type specifier}}) as a friend of this class. This means that the friend's member declarations and definitions can access private and protected members of this class and also that the friend can inherit from private and protected members of this class.
+
 
The name of the class that is used in this {{tt|friend}} declaration does not need to be previously declared.
+
@3,4@ Designates a class as a friend of this class. This means that the friend's member declarations and definitions can access private and protected members of this class and also that the friend can inherit from private and protected members of this class.
@4@ Designates the type named by the {{spar|simple-type-specifier}} or {{spar|typename-specifier}} as a friend of this class if that type is a (possibly {{rlp|cv|cv-qualified}}) class, struct, or union; otherwise the {{tt|friend}} declaration is ignored. This declaration will not forward declare a new type.
+
 
 +
:@3@ The class is named by {{spar|elaborated-type-specifier}}. The name of the class that is used in this friend declaration does not need to be previously declared.
 +
 
 +
:@4@ The class is named by {{spar|simple-type-specifier}} or {{spar|typename-specifier}}. If the named type is not a class type, this friend declaration is ignored. This declaration will not forward declare a new type.
 +
 
 +
@5@ Designates all classes in {{spar|friend-type-specifier-list}} as a friend of this class. This means that the friends' member declarations and definitions can access private and protected members of this class and also that the friends can inherit from private and protected members of this class. If a named type is not a class type, it is ignored in this friend declaration.
 +
 
 +
@@ Each specifier in {{spar|friend-type-specifier-list}} names a class if the specifier is not followed by an ellipsis, otherwise {{rlp|parameter pack#Friend declarations|pack expansion}} applies.
 
{{source|1=
 
{{source|1=
 
class Y {};
 
class Y {};
class A {
+
 
 +
class A
 +
{
 
     int data; // private data member
 
     int data; // private data member
     class B { }; // private nested type
+
   
 +
     class B {}; // private nested type
 +
   
 
     enum { a = 100 }; // private enumerator
 
     enum { a = 100 }; // private enumerator
 +
   
 
     friend class X; // friend class forward declaration (elaborated class specifier)
 
     friend class X; // friend class forward declaration (elaborated class specifier)
     friend Y; // friend class declaration (simple type specifier) (since c++11)
+
     friend Y; // friend class declaration (simple type specifier) (since C++11)
 +
   
 +
    // the two friend declarations above can be merged since C++26:
 +
    // friend class X, Y;
 
};
 
};
  
class X : A::B { // OK: A::B accessible to friend
+
class X : A::B // OK: A::B accessible to friend
 +
{
 
     A::B mx; // OK: A::B accessible to member of friend
 
     A::B mx; // OK: A::B accessible to member of friend
     class Y {
+
   
 +
     class Y
 +
    {
 
         A::B my; // OK: A::B accessible to nested member of friend
 
         A::B my; // OK: A::B accessible to nested member of friend
 
     };
 
     };
 +
   
 
     int v[A::a]; // OK: A::a accessible to member of friend
 
     int v[A::a]; // OK: A::a accessible to member of friend
 
};
 
};
 
}}
 
}}
 
===Notes===
 
Friendship is not transitive (a friend of your friend is not your friend).
 
 
Friendship is not inherited (your friend's children are not your friends).
 
 
Storage class specifiers are not allowed in friend function declarations. A function that is defined in the friend declaration has external linkage, a function that was previously defined, keeps the linkage it was defined with.
 
 
{{rlp|access|Access specifiers}} have no effect on the meaning of friend declarations (they can appear in {{tt|private:}} or in {{tt|public:}} sections, with no difference).
 
 
A friend class declaration cannot define a new class ({{c|friend class X {};}} is an error).
 
 
When a local class declares an unqualified function or class as a friend, only functions and classes in the innermost non-class scope are {{rlp|lookup|looked up}}, not the global functions:
 
{{source|class F {};
 
int f();
 
int main()
 
{
 
    extern int g();
 
    class Local { // Local class in the main() function
 
        friend int f(); // Error, no such function declared in main()
 
        friend int g(); // OK, there is a declaration for g in main()
 
        friend class F; // friends a local F (defined later)
 
        friend class ::F; // friends the global F
 
    };
 
    class F {}; // local F
 
}
 
}}
 
 
A name first declared in a friend declaration within a class or class template X becomes a member of the innermost enclosing namespace of X, but is not visible for lookup (except argument-dependent lookup that considers X) unless a matching declaration at the namespace scope is provided - see {{rlp|namespace#Namespaces|namespaces}} for details.
 
  
 
===Template friends===
 
===Template friends===
 
Both {{rlp|function template}} and {{rlp|class template}} declarations may appear with the {{tt|friend}} specifier in any non-local class or class template (although only function templates may be defined within the class or class template that is granting friendship). In this case, every specialization of the template becomes a friend, whether it is implicitly instantiated, partially specialized, or explicitly specialized.
 
Both {{rlp|function template}} and {{rlp|class template}} declarations may appear with the {{tt|friend}} specifier in any non-local class or class template (although only function templates may be defined within the class or class template that is granting friendship). In this case, every specialization of the template becomes a friend, whether it is implicitly instantiated, partially specialized, or explicitly specialized.
  
{{source|class A {
+
{{source|
 +
class A
 +
{
 
     template<typename T>
 
     template<typename T>
 
     friend class B; // every B<T> is a friend of A
 
     friend class B; // every B<T> is a friend of A
 
+
   
 
     template<typename T>
 
     template<typename T>
 
     friend void f(T) {} // every f<T> is a friend of A
 
     friend void f(T) {} // every f<T> is a friend of A
Line 109: Line 124:
  
 
{{source|
 
{{source|
template<class T> class A {}; // primary
+
template<class T>
template<class T> class A<T*> {}; // partial
+
class A {};     // primary
template<> class A<int> {}; // full
+
 
class X {
+
template<class T>
     template<class T> friend class A<T*>; // error!
+
class A<T*> {}; // partial
 +
 
 +
template<>
 +
class A<int> {}; // full
 +
 
 +
class X
 +
{
 +
     template<class T>
 +
    friend class A<T*>; // Error
 +
   
 
     friend class A<int>; // OK
 
     friend class A<int>; // OK
 
};
 
};
 
}}
 
}}
  
When a friend declaration refers to a full specialization of a function template, the keyword {{tt|inline}} and default arguments cannot be used.
+
When a friend declaration refers to a full specialization of a function template, the keyword {{c/core|inline}}{{rev inl|since=c++11|, {{c/core|constexpr}}}}{{rev inl|since=c++20|, {{c/core|consteval}}}} and default arguments cannot be used:
  
 
{{source|1=
 
{{source|1=
template<class T> void f(int);
+
template<class T>
template<> void f<int>(int);
+
void f(int);
  
class X {
+
template<>
 +
void f<int>(int);
 +
 
 +
class X
 +
{
 
     friend void f<int>(int x = 1); // error: default args not allowed
 
     friend void f<int>(int x = 1); // error: default args not allowed
 
};
 
};
Line 130: Line 158:
  
 
<!-- based on post-CWG 1862 wording of [temp.friend]p4-->
 
<!-- based on post-CWG 1862 wording of [temp.friend]p4-->
A template friend declaration can name a member of a class template A, which can be either a member function or a member type (the type must use {{rlp|elaborated_type_specifier|elaborated-type-specifier}}). Such declaration is only well-formed if the last component in its nested-name-specifier (the name to the left of the last {{ttb|::}}) is a simple-template-id (template name followed by argument list in angle brackets) that names the class template. The template parameters of such template friend declaration must be deducible from the simple-template-id.
+
A template friend declaration can name a member of a class template A, which can be either a member function or a member type (the type must use {{rlp|elaborated type specifier|elaborated-type-specifier}}). Such declaration is only well-formed if the last component in its nested-name-specifier (the name to the left of the last {{ttb|::}}) is a simple-template-id (template name followed by argument list in angle brackets) that names the class template. The template parameters of such template friend declaration must be deducible from the simple-template-id.
  
In this case, the member of any specialization of A becomes a friend. This does not involve instantiating the primary template A: the only requirements are that the deduction of the template parameters of A from that specialization succeeds, and that substitution of the deduced template arguments into the friend declaration produces a declaration that would be a valid redeclaration of the member of the specialization:
+
In this case, the member of any specialization of either A or partial specializations of A becomes a friend. This does not involve instantiating the primary template A or partial specializations of A: the only requirements are that the deduction of the template parameters of A from that specialization succeeds, and that substitution of the deduced template arguments into the friend declaration produces a declaration that would be a valid redeclaration of the member of the specialization:
  
 
{{source|
 
{{source|
 
// primary template
 
// primary template
 
template<class T>
 
template<class T>
struct A {  
+
struct A
  struct B { };
+
{  
  void f();
+
    struct B {};
  struct D { void g(); };
+
   
  T h();
+
    void f();
  template<T U> T i();
+
   
 +
    struct D { void g(); };
 +
   
 +
    T h();
 +
   
 +
    template<T U>
 +
    T i();
 
};
 
};
 +
 
// full specialization
 
// full specialization
 
template<>
 
template<>
struct A<int> {
+
struct A<int>
  struct B { };
+
{
  int f();
+
    struct B {};
  struct D { void g(); };
+
   
  template<int U> int i();
+
    int f();
 +
   
 +
    struct D { void g(); };
 +
   
 +
    template<int U>
 +
    int i();
 
};
 
};
 +
 
// another full specialization
 
// another full specialization
 
template<>
 
template<>
struct A<float*> {
+
struct A<float*>
 +
{
 
     int *h();
 
     int *h();
 
};
 
};
// the non-template class granting friendship to members of class template A
 
class X {
 
  template<class T>
 
  friend struct A<T>::B; // all A<T>::B are friends, including A<int>::B
 
 
  template<class T>
 
  friend void A<T>::f();  // A<int>::f() is not a friend because its signature
 
                          // does not match, but e.g. A<char>::f() is a friend
 
  
 +
// the non-template class granting friendship to members of class template A
 +
class X
 +
{
 +
    template<class T>
 +
    friend struct A<T>::B; // all A<T>::B are friends, including A<int>::B
 +
   
 +
    template<class T>
 +
    friend void A<T>::f(); // A<int>::f() is not a friend because its signature
 +
                          // does not match, but e.g. A<char>::f() is a friend
 +
   
 
//  template<class T>
 
//  template<class T>
 
//  friend void A<T>::D::g(); // ill-formed, the last part of the nested-name-specifier,
 
//  friend void A<T>::D::g(); // ill-formed, the last part of the nested-name-specifier,
 
//                            // D in A<T>::D::, is not simple-template-id
 
//                            // D in A<T>::D::, is not simple-template-id
 
+
   
  template<class T>
+
    template<class T>
  friend int* A<T*>::h(); // all A<T*>::h are friends: A<float*>::h(), A<int*>::h(), etc
+
    friend int* A<T*>::h(); // all A<T*>::h are friends:
 
+
                            // A<float*>::h(), A<int*>::h(), etc
  template<class T>  
+
   
  template<T U>      // all instantiations of A<T>::i() and A<int>::i() are friends,  
+
    template<class T>  
  friend T A<T>::i(); // and thereby all specializations of those function templates
+
    template<T U>      // all instantiations of A<T>::i() and A<int>::i() are friends,  
 +
    friend T A<T>::i(); // and thereby all specializations of those function templates
 
};
 
};
 
}}
 
}}
Line 181: Line 226:
 
{{rev begin}}
 
{{rev begin}}
 
{{rev|since=c++11|
 
{{rev|since=c++11|
{{rlp|template_parameters#Default_template_arguments|Default template arguments}} are only allowed on template friend declarations if the declaration is a definition and no other declarations of this function template appear in this translation unit.
+
{{rlp|template parameters#Default template arguments|Default template arguments}} are only allowed on template friend declarations if the declaration is a definition and no other declarations of this function template appear in this translation unit.
 
}}
 
}}
 
{{rev end}}
 
{{rev end}}
  
 
===Template friend operators===
 
===Template friend operators===
A common use case for template friends is declaration of a non-member operator overload that acts on a class template, e.g. {{c|operator<<(std::ostream&, const Foo<T>&)}} for some user-defined {{c|Foo<T>}}
+
A common use case for template friends is declaration of a non-member operator overload that acts on a class template, e.g. {{c|operator<<(std::ostream&, const Foo<T>&)}} for some user-defined {{c|Foo<T>}}.
  
Such operator can be defined in the class body, which has the effect of generating a separate non-template {{tt|operator<<}} for each {{tt|T}} and makes that non-template {{tt|operator<<}} a friend of its {{tt|Foo<T>}}
+
Such operator can be defined in the class body, which has the effect of generating a separate non-template {{c|operator<<}} for each {{tt|T}} and makes that non-template {{c|operator<<}} a friend of its {{c|Foo<T>}}:
  
{{example|code=#include <iostream>
+
{{example|code=
 +
#include <iostream>
  
 
template<typename T>
 
template<typename T>
class Foo {
+
class Foo
public:
+
{
 +
public:
 
     Foo(const T& val) : data(val) {}
 
     Foo(const T& val) : data(val) {}
private:
+
private:
 
     T data;
 
     T data;
 
+
   
 
     // generates a non-template operator<< for this T
 
     // generates a non-template operator<< for this T
 
     friend std::ostream& operator<<(std::ostream& os, const Foo& obj)
 
     friend std::ostream& operator<<(std::ostream& os, const Foo& obj)
Line 214: Line 261:
 
}}
 
}}
  
or the function template has to be declared as a template before the class body, in which case the friend declaration within {{tt|Foo<T>}} can refer to the full specialization of {{tt|operator<<}} for its {{tt|T}}:
+
or the function template has to be declared as a template before the class body, in which case the friend declaration within {{c|Foo<T>}} can refer to the full specialization of {{c|operator<<}} for its {{tt|T}}:
  
 
{{example|code=
 
{{example|code=
Line 226: Line 273:
  
 
template<typename T>
 
template<typename T>
class Foo {
+
class Foo
public:
+
{
 +
public:
 
     Foo(const T& val) : data(val) {}
 
     Foo(const T& val) : data(val) {}
private:
+
private:
 
     T data;
 
     T data;
 
+
   
 
     // refers to a full specialization for this particular T  
 
     // refers to a full specialization for this particular T  
 
     friend std::ostream& operator<< <> (std::ostream&, const Foo&);
 
     friend std::ostream& operator<< <> (std::ostream&, const Foo&);
 +
   
 
     // note: this relies on template argument deduction in declarations
 
     // note: this relies on template argument deduction in declarations
 
     // can also specify the template argument with operator<< <T>"
 
     // can also specify the template argument with operator<< <T>"
Line 251: Line 300:
 
}
 
}
 
}}
 
}}
 +
 +
===Linkage===
 +
{{rlp|storage duration|Storage class specifiers}} are not allowed in friend declarations.
 +
 +
{{rrev|since=c++20|
 +
If a function or function template is first declared and defined in a friend declaration, and the enclosing class is defined within an {{rlp|modules#Exporting declarations and definitions|exporting declarations}}, its name has the same linkage as the name of the enclosing class.
 +
}}
 +
 +
{{rev inl|until=c++20|If}}{{rev inl|since=c++20|Otherwise, if}} a function or function template is declared in a friend declaration, and a {{rlp|conflicting declarations#Corresponding declarations|corresponding non-friend declaration}} is reachable, the name has the linkage determined from that prior declaration.
 +
 +
Otherwise, the linkage of the name introduced by a friend declaration is determined as usual.
 +
 +
===Notes===
 +
Friendship is not transitive (a friend of your friend is not your friend).
 +
 +
Friendship is not inherited (your friend's children are not your friends, and your friends are not your children's friends).
 +
 +
{{rlp|access|Access specifiers}} have no effect on the meaning of friend declarations (they can appear in {{c/core|private:}} or in {{c/core|public:}} sections, with no difference).
 +
 +
A friend class declaration cannot define a new class ({{c|friend class X {};}} is an error).
 +
 +
When a local class declares an unqualified function or class as a friend, only functions and classes in the innermost non-class scope are {{rlp|lookup|looked up}}, not the global functions:
 +
{{source|
 +
class F {};
 +
 +
int f();
 +
 +
int main()
 +
{
 +
    extern int g();
 +
   
 +
    class Local // Local class in the main() function
 +
    {
 +
        friend int f(); // Error, no such function declared in main()
 +
        friend int g(); // OK, there is a declaration for g in main()
 +
        friend class F; // friends a local F (defined later)
 +
        friend class ::F; // friends the global F
 +
    };
 +
   
 +
    class F {}; // local F
 +
}
 +
}}
 +
 +
A name first declared in a friend declaration within a class or class template {{tt|X}} becomes a member of the innermost enclosing namespace of {{tt|X}}, but is not visible for lookup (except argument-dependent lookup that considers {{tt|X}}) unless a matching declaration at namespace scope is provided - see {{rlp|namespace#Namespaces|namespaces}} for details.
 +
 +
{{feature test macro|__cpp_variadic_friend|Variadic friend declarations|value=202403L|std=C++26}}
 +
 +
===Keywords===
 +
{{ltt|cpp/keyword/friend}}
  
 
===Example===
 
===Example===
 
{{example
 
{{example
| stream insertion and extraction operators are often declared as non-member friends
+
|Stream insertion and extraction operators are often declared as non-member friends:
| code=#include <iostream>
+
|code=
 +
#include <iostream>
 
#include <sstream>
 
#include <sstream>
  
class MyClass {
+
class MyClass
     int i;
+
{
 
+
     int i;                   // friends have access to non-public, non-static
     friend std::ostream& operator<<(std::ostream& out, const MyClass& o);
+
    static inline int id{6}; // and static (possibly inline) members
     friend std::istream& operator>>(std::istream& in, MyClass& o);
+
   
public:
+
     friend std::ostream& operator<<(std::ostream& out, const MyClass&);
 +
     friend std::istream& operator>>(std::istream& in, MyClass&);
 +
    friend void change_id(int);
 +
public:
 
     MyClass(int i = 0) : i(i) {}
 
     MyClass(int i = 0) : i(i) {}
 
};
 
};
Line 269: Line 371:
 
std::ostream& operator<<(std::ostream& out, const MyClass& mc)
 
std::ostream& operator<<(std::ostream& out, const MyClass& mc)
 
{
 
{
     return out << mc.i;
+
     return out << "MyClass::id = " << MyClass::id << "; i = " << mc.i;
 
}
 
}
  
Line 276: Line 378:
 
     return in >> mc.i;
 
     return in >> mc.i;
 
}
 
}
 +
 +
void change_id(int id) { MyClass::id = id; }
  
 
int main()
 
int main()
Line 281: Line 385:
 
     MyClass mc(7);
 
     MyClass mc(7);
 
     std::cout << mc << '\n';
 
     std::cout << mc << '\n';
 +
//  mc.i = 333*2;  // error: i is a private member
 
     std::istringstream("100") >> mc;
 
     std::istringstream("100") >> mc;
 +
    std::cout << mc << '\n';
 +
//  MyClass::id = 222*3;  // error: id is a private member
 +
    change_id(9);
 
     std::cout << mc << '\n';
 
     std::cout << mc << '\n';
 
}
 
}
 
|output=
 
|output=
7
+
MyClass::id = 6; i = 7
100
+
MyClass::id = 6; i = 100
 +
MyClass::id = 9; i = 100
 
}}
 
}}
  
 
===Defect reports===
 
===Defect reports===
 
{{dr list begin}}
 
{{dr list begin}}
{{dr list item|wg=cwg|dr=45|std=C++98|before=members of a class nested in a friend class of {{tt|T}} have no special access to {{tt|T}}|after=a nested class has the same access as the enclosing class}}
+
{{dr list item|wg=cwg|dr=45|std=C++98|before=members of a class nested in a friend<br>class of {{tt|T}} have no special access to {{tt|T}}|after=a nested class has the same<br>access as the enclosing class}}
{{dr list item|wg=cwg|dr=500|std=C++98|before=friend class of {{tt|T}} cannot inherit from private or protected members of {{tt|T}}, but its nested class can|after=both can inherit from such members}}
+
{{dr list item|wg=cwg|dr=500|std=C++98|before=friend class of {{tt|T}} cannot inherit from private or<br>protected members of {{tt|T}}, but its nested class can|after=both can inherit<br>from such members}}
 +
{{dr list item|wg=cwg|dr=1439|std=C++98|before=the rule targeting friend declarations in non-local<br>classes did not cover template declarations|after=covered}}
 +
{{dr list item|wg=cwg|dr=1477|std=C++98|before=a name first declared in a friend declaration within a class<br>or class template was not visible for lookup if the matching<br>declaration is provided in another namespace scope|after=it is visible for<br>lookup in this case}}
 +
{{dr list item|wg=cwg|dr=1804|std=C++98|before=when a member of a class template is friended, the corresponding<br>member of specializations of partial specializations of the class<br>template was not a friend of the class granting friendship|after=such members<br>are also friends}}
 +
{{dr list item|wg=cwg|dr=2379|std=C++11|before=friend declarations referring to full specializations<br>of function templates could be declared constexpr|after=prohibited}}
 +
{{dr list item|wg=cwg|dr=2588|std=C++98|before=the linkages of names introduced by friend declarations were unclear|after=made clear}}
 
{{dr list end}}
 
{{dr list end}}
  
 
===References===
 
===References===
 +
{{ref std c++23}}
 +
{{ref std|section=11.8.4|title=Friends|id=class.friend}}
 +
{{ref std|section=13.7.5|title=Friends|id=temp.friend}}
 +
{{ref std end}}
 +
{{ref std c++20}}
 +
{{ref std|section=11.9.3|title=Friends|id=class.friend}}
 +
{{ref std|section=13.7.4|title=Friends|id=temp.friend}}
 +
{{ref std end}}
 +
{{ref std c++17}}
 +
{{ref std|section=14.3|title=Friends|id=class.friend}}
 +
{{ref std|section=17.5.4|title=Friends|id=temp.friend}}
 +
{{ref std end}}
 +
{{ref std c++14}}
 +
{{ref std|section=11.3|title=Friends|id=class.friend}}
 +
{{ref std|section=14.5.4|title=Friends|id=temp.friend}}
 +
{{ref std end}}
 
{{ref std c++11}}
 
{{ref std c++11}}
{{ref std | section=11.3 | title=Friends | id=class.friend}}
+
{{ref std|section=11.3|title=Friends|id=class.friend}}
{{ref std | section=14.5.4 | title=Friends | id=temp.friend}}
+
{{ref std|section=14.5.4|title=Friends|id=temp.friend}}
 
{{ref std end}}
 
{{ref std end}}
 
{{ref std c++98}}
 
{{ref std c++98}}
{{ref std | section=11.3 | title=Friends | id=class.friend}}
+
{{ref std|section=11.3|title=Friends|id=class.friend}}
{{ref std | section=14.5.3 | title=Friends | id=temp.friend}}
+
{{ref std|section=14.5.3|title=Friends|id=temp.friend}}
 
{{ref std end}}
 
{{ref std end}}
  
 
===See also===
 
===See also===
 
{{dsc begin}}
 
{{dsc begin}}
{{dsc | [[cpp/language/class | Class declaration ]] }}
+
{{dsc inc|cpp/language/dsc class}}
{{dsc | [[cpp/language/access | Access specifiers ]] }}
+
{{dsc inc|cpp/language/dsc access}}
 
{{dsc end}}
 
{{dsc end}}
  
 
{{langlinks|de|es|fr|it|ja|pt|ru|zh}}
 
{{langlinks|de|es|fr|it|ja|pt|ru|zh}}

Latest revision as of 22:41, 11 August 2024

 
 
C++ language
General topics
Flow control
Conditional execution statements
if
Iteration statements (loops)
for
range-for (C++11)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications (until C++17*)
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Access specifiers
friend specifier

Class-specific function properties
explicit (C++11)
static

Special member functions
Templates
Miscellaneous
 
 

The friend declaration appears in a class body and grants a function or another class access to private and protected members of the class where the friend declaration appears.

Contents

[edit] Syntax

friend function-declaration (1)
friend function-definition (2)
friend elaborated-type-specifier ; (3) (until C++26)
friend simple-type-specifier ;

friend typename-specifier ;

(4) (since C++11)
(until C++26)
friend friend-type-specifier-list ; (5) (since C++26)
1,2) A function friend declaration.
3-5) A class friend declaration.
function-declaration - a function declaration
function-definition - a function definition
elaborated-type-specifier - an elaborated type specifier
simple-type-specifier - a simple type specifier
typename-specifier - the keyword typename followed by a qualified identifier or qualified simple template identifier
friend-type-specifier-list - a non-empty comma-separated list of simple-type-specifier, elaborated-type-specifier, and typename-specifier s, each specifier can be followed by an ellipsis (...)

[edit] Description

1) Designates a function or several functions as friends of this class:
class Y
{
    int data; // private member
 
    // the non-member function operator<< will have access to Y's private members
    friend std::ostream& operator<<(std::ostream& out, const Y& o);
    friend char* X::foo(int); // members of other classes can be friends too
    friend X::X(char), X::~X(); // constructors and destructors can be friends
};
 
// friend declaration does not declare a member function
// this operator<< still needs to be defined, as a non-member
std::ostream& operator<<(std::ostream& out, const Y& y)
{
    return out << y.data; // can access private member Y::data
}
2) (only allowed in non-local class definitions) Defines a non-member function, and makes it a friend of this class at the same time. Such non-member function is always inline, unless it is attached to a named module(since C++20).
class X
{
    int a;
 
    friend void friend_set(X& p, int i)
    {
        p.a = i; // this is a non-member function
    }
public:
    void member_set(int i)
    {
        a = i; // this is a member function
    }
};
3,4) Designates a class as a friend of this class. This means that the friend's member declarations and definitions can access private and protected members of this class and also that the friend can inherit from private and protected members of this class.
3) The class is named by elaborated-type-specifier. The name of the class that is used in this friend declaration does not need to be previously declared.
4) The class is named by simple-type-specifier or typename-specifier. If the named type is not a class type, this friend declaration is ignored. This declaration will not forward declare a new type.
5) Designates all classes in friend-type-specifier-list as a friend of this class. This means that the friends' member declarations and definitions can access private and protected members of this class and also that the friends can inherit from private and protected members of this class. If a named type is not a class type, it is ignored in this friend declaration.
Each specifier in friend-type-specifier-list names a class if the specifier is not followed by an ellipsis, otherwise pack expansion applies.
class Y {};
 
class A
{
    int data; // private data member
 
    class B {}; // private nested type
 
    enum { a = 100 }; // private enumerator
 
    friend class X; // friend class forward declaration (elaborated class specifier)
    friend Y; // friend class declaration (simple type specifier) (since C++11)
 
    // the two friend declarations above can be merged since C++26:
    // friend class X, Y;
};
 
class X : A::B // OK: A::B accessible to friend
{
    A::B mx; // OK: A::B accessible to member of friend
 
    class Y
    {
        A::B my; // OK: A::B accessible to nested member of friend
    };
 
    int v[A::a]; // OK: A::a accessible to member of friend
};

[edit] Template friends

Both function template and class template declarations may appear with the friend specifier in any non-local class or class template (although only function templates may be defined within the class or class template that is granting friendship). In this case, every specialization of the template becomes a friend, whether it is implicitly instantiated, partially specialized, or explicitly specialized.

class A
{
    template<typename T>
    friend class B; // every B<T> is a friend of A
 
    template<typename T>
    friend void f(T) {} // every f<T> is a friend of A
};

Friend declarations cannot refer to partial specializations, but can refer to full specializations:

template<class T>
class A {};      // primary
 
template<class T>
class A<T*> {};  // partial
 
template<>
class A<int> {}; // full
 
class X
{
    template<class T>
    friend class A<T*>;  // Error
 
    friend class A<int>; // OK
};

When a friend declaration refers to a full specialization of a function template, the keyword inline, constexpr(since C++11), consteval(since C++20) and default arguments cannot be used:

template<class T>
void f(int);
 
template<>
void f<int>(int);
 
class X
{
    friend void f<int>(int x = 1); // error: default args not allowed
};

A template friend declaration can name a member of a class template A, which can be either a member function or a member type (the type must use elaborated-type-specifier). Such declaration is only well-formed if the last component in its nested-name-specifier (the name to the left of the last ::) is a simple-template-id (template name followed by argument list in angle brackets) that names the class template. The template parameters of such template friend declaration must be deducible from the simple-template-id.

In this case, the member of any specialization of either A or partial specializations of A becomes a friend. This does not involve instantiating the primary template A or partial specializations of A: the only requirements are that the deduction of the template parameters of A from that specialization succeeds, and that substitution of the deduced template arguments into the friend declaration produces a declaration that would be a valid redeclaration of the member of the specialization:

// primary template
template<class T>
struct A
{ 
    struct B {};
 
    void f();
 
    struct D { void g(); };
 
    T h();
 
    template<T U>
    T i();
};
 
// full specialization
template<>
struct A<int>
{
    struct B {};
 
    int f();
 
    struct D { void g(); };
 
    template<int U>
    int i();
};
 
// another full specialization
template<>
struct A<float*>
{
    int *h();
};
 
// the non-template class granting friendship to members of class template A
class X
{
    template<class T>
    friend struct A<T>::B; // all A<T>::B are friends, including A<int>::B
 
    template<class T>
    friend void A<T>::f(); // A<int>::f() is not a friend because its signature
                           // does not match, but e.g. A<char>::f() is a friend
 
//  template<class T>
//  friend void A<T>::D::g(); // ill-formed, the last part of the nested-name-specifier,
//                            // D in A<T>::D::, is not simple-template-id
 
    template<class T>
    friend int* A<T*>::h(); // all A<T*>::h are friends:
                            // A<float*>::h(), A<int*>::h(), etc
 
    template<class T> 
    template<T U>       // all instantiations of A<T>::i() and A<int>::i() are friends, 
    friend T A<T>::i(); // and thereby all specializations of those function templates
};

Default template arguments are only allowed on template friend declarations if the declaration is a definition and no other declarations of this function template appear in this translation unit.

(since C++11)

[edit] Template friend operators

A common use case for template friends is declaration of a non-member operator overload that acts on a class template, e.g. operator<<(std::ostream&, const Foo<T>&) for some user-defined Foo<T>.

Such operator can be defined in the class body, which has the effect of generating a separate non-template operator<< for each T and makes that non-template operator<< a friend of its Foo<T>:

#include <iostream>
 
template<typename T>
class Foo
{
public:
    Foo(const T& val) : data(val) {}
private:
    T data;
 
    // generates a non-template operator<< for this T
    friend std::ostream& operator<<(std::ostream& os, const Foo& obj)
    {
        return os << obj.data;
    }
};
 
int main()
{
    Foo<double> obj(1.23);
    std::cout << obj << '\n';
}

Output:

1.23

or the function template has to be declared as a template before the class body, in which case the friend declaration within Foo<T> can refer to the full specialization of operator<< for its T:

#include <iostream>
 
template<typename T>
class Foo; // forward declare to make function declaration possible
 
template<typename T> // declaration
std::ostream& operator<<(std::ostream&, const Foo<T>&);
 
template<typename T>
class Foo
{
public:
    Foo(const T& val) : data(val) {}
private:
    T data;
 
    // refers to a full specialization for this particular T 
    friend std::ostream& operator<< <> (std::ostream&, const Foo&);
 
    // note: this relies on template argument deduction in declarations
    // can also specify the template argument with operator<< <T>"
};
 
// definition
template<typename T>
std::ostream& operator<<(std::ostream& os, const Foo<T>& obj)
{
    return os << obj.data;
}
 
int main()
{
    Foo<double> obj(1.23);
    std::cout << obj << '\n';
}

[edit] Linkage

Storage class specifiers are not allowed in friend declarations.

If a function or function template is first declared and defined in a friend declaration, and the enclosing class is defined within an exporting declarations, its name has the same linkage as the name of the enclosing class.

(since C++20)

If(until C++20)Otherwise, if(since C++20) a function or function template is declared in a friend declaration, and a corresponding non-friend declaration is reachable, the name has the linkage determined from that prior declaration.

Otherwise, the linkage of the name introduced by a friend declaration is determined as usual.

[edit] Notes

Friendship is not transitive (a friend of your friend is not your friend).

Friendship is not inherited (your friend's children are not your friends, and your friends are not your children's friends).

Access specifiers have no effect on the meaning of friend declarations (they can appear in private: or in public: sections, with no difference).

A friend class declaration cannot define a new class (friend class X {}; is an error).

When a local class declares an unqualified function or class as a friend, only functions and classes in the innermost non-class scope are looked up, not the global functions:

class F {};
 
int f();
 
int main()
{
    extern int g();
 
    class Local // Local class in the main() function
    {
        friend int f(); // Error, no such function declared in main()
        friend int g(); // OK, there is a declaration for g in main()
        friend class F; // friends a local F (defined later)
        friend class ::F; // friends the global F
    };
 
    class F {}; // local F
}

A name first declared in a friend declaration within a class or class template X becomes a member of the innermost enclosing namespace of X, but is not visible for lookup (except argument-dependent lookup that considers X) unless a matching declaration at namespace scope is provided - see namespaces for details.

Feature-test macro Value Std Feature
__cpp_variadic_friend 202403L (C++26) Variadic friend declarations

[edit] Keywords

friend

[edit] Example

Stream insertion and extraction operators are often declared as non-member friends:

#include <iostream>
#include <sstream>
 
class MyClass
{
    int i;                   // friends have access to non-public, non-static
    static inline int id{6}; // and static (possibly inline) members
 
    friend std::ostream& operator<<(std::ostream& out, const MyClass&);
    friend std::istream& operator>>(std::istream& in, MyClass&);
    friend void change_id(int);
public:
    MyClass(int i = 0) : i(i) {}
};
 
std::ostream& operator<<(std::ostream& out, const MyClass& mc)
{
    return out << "MyClass::id = " << MyClass::id << "; i = " << mc.i;
}
 
std::istream& operator>>(std::istream& in, MyClass& mc)
{
    return in >> mc.i;
}
 
void change_id(int id) { MyClass::id = id; }
 
int main()
{
    MyClass mc(7);
    std::cout << mc << '\n';
//  mc.i = 333*2;  // error: i is a private member
    std::istringstream("100") >> mc;
    std::cout << mc << '\n';
//  MyClass::id = 222*3;  // error: id is a private member
    change_id(9);
    std::cout << mc << '\n';
}

Output:

MyClass::id = 6; i = 7
MyClass::id = 6; i = 100
MyClass::id = 9; i = 100

[edit] Defect reports

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

DR Applied to Behavior as published Correct behavior
CWG 45 C++98 members of a class nested in a friend
class of T have no special access to T
a nested class has the same
access as the enclosing class
CWG 500 C++98 friend class of T cannot inherit from private or
protected members of T, but its nested class can
both can inherit
from such members
CWG 1439 C++98 the rule targeting friend declarations in non-local
classes did not cover template declarations
covered
CWG 1477 C++98 a name first declared in a friend declaration within a class
or class template was not visible for lookup if the matching
declaration is provided in another namespace scope
it is visible for
lookup in this case
CWG 1804 C++98 when a member of a class template is friended, the corresponding
member of specializations of partial specializations of the class
template was not a friend of the class granting friendship
such members
are also friends
CWG 2379 C++11 friend declarations referring to full specializations
of function templates could be declared constexpr
prohibited
CWG 2588 C++98 the linkages of names introduced by friend declarations were unclear made clear

[edit] References

  • C++23 standard (ISO/IEC 14882:2024):
  • 11.8.4 Friends [class.friend]
  • 13.7.5 Friends [temp.friend]
  • C++20 standard (ISO/IEC 14882:2020):
  • 11.9.3 Friends [class.friend]
  • 13.7.4 Friends [temp.friend]
  • C++17 standard (ISO/IEC 14882:2017):
  • 14.3 Friends [class.friend]
  • 17.5.4 Friends [temp.friend]
  • C++14 standard (ISO/IEC 14882:2014):
  • 11.3 Friends [class.friend]
  • 14.5.4 Friends [temp.friend]
  • C++11 standard (ISO/IEC 14882:2011):
  • 11.3 Friends [class.friend]
  • 14.5.4 Friends [temp.friend]
  • C++98 standard (ISO/IEC 14882:1998):
  • 11.3 Friends [class.friend]
  • 14.5.3 Friends [temp.friend]

[edit] See also

Class types defines types holding several data members [edit]
Access specifiers defines visibility of class members[edit]