C++ The friend Keyword
Introduction to the friend Keyword
In C++, the friend
keyword allows a non-member function, another class, or a specific member function of another class to access a class’s private and protected members.
A friend is not a class member; it only gains access privileges. Declaring friendship is a way for a class to explicitly grant access to its internals.
Why Use the friend Keyword?
- Special Access Needs: Sometimes two entities must collaborate closely and need access to internal state.
- Operator Overloading: Common for symmetric non-member operators (e.g., operator<<
) that require access to private data.
- Coupled Types: When two types naturally need to inspect each other’s internals in a controlled manner.
Friend Function Example
A friend function is not a member of the class but has access to its private and protected members.
#include <iostream>
using namespace std;
class Box {
private:
double width;
public:
Box(double w) : width(w) {}
// Friend function declaration
friend void printWidth(const Box& b);
};
// Friend function definition at namespace scope
void printWidth(const Box& b) {
cout << "Width: " << b.width << endl; // Accessing private member
}
int main() {
Box b1(5.5);
printWidth(b1);
return 0;
}
Width: 5.5
Friend Class Example
When one class is declared as a friend of another, all member functions of the friend class can access the private and protected members of the granting class.
#include <iostream>
using namespace std;
class Engine {
private:
int horsepower;
public:
Engine(int hp) : horsepower(hp) {}
friend class Car; // Car can access private members
};
class Car {
public:
void showEnginePower(const Engine& e) {
cout << "Engine Power: " << e.horsepower << " HP" << endl;
}
};
int main() {
Engine e1(300);
Car c1;
c1.showEnginePower(e1);
return 0;
}
Engine Power: 300 HP
Friend Member Function Example (Correct Forward Declarations)
To befriend a specific member function, that function must be declared before the friendship is granted. Use forward declarations to make this work.
#include <iostream>
using namespace std;
class A; // forward declare A so B can mention it
class B {
public:
void revealSecret(const A& a) const; // declare member to be friended
};
class A {
private:
int secret = 42;
// Befriend exactly B::revealSecret with matching signature
friend void B::revealSecret(const A&) const;
};
void B::revealSecret(const A& a) const {
cout << "Secret = " << a.secret << '\n';
}
int main() {
A a; B b; b.revealSecret(a);
}
Secret = 42
Friend and Operator Overloading
A common use of friend
is to implement I/O operators that need access to private members while remaining non-members (to preserve symmetric conversions).
#include <iostream>
#include <string>
using namespace std;
class User {
string name;
public:
explicit User(string n) : name(move(n)) {}
friend ostream& operator<<(ostream& os, const User& u) {
return os << "User{" << u.name << "}";
}
};
int main() {
User u("Ada");
cout << u << '\n';
}
User{Ada}
Important Notes
- Friendship is not inherited: a derived class does not gain friendship automatically.
- Friendship is not reciprocal: if A is a friend of B, B is not automatically a friend of A.
- Friendship is not transitive: if A befriends B and B befriends C, A is not a friend of C.
- Friendship is granted by the class being accessed, and it applies to the type, not to individual objects.
- Friend declarations can appear in any access section (public/private/protected); their placement does not change the level of access for other members.
Best Practices
- Use friend
sparingly and document why it is needed.
- Prefer minimal exposure: friend a specific function instead of an entire class when possible.
- Consider alternative designs (public accessors, non-friend helper APIs) if they keep encapsulation intact without undue complexity.