Lesson 4 | Friend functions |
Objective | How and where to declare a friend function. |
Where to declare C++ Friend Function
Before continuing our exploration of operator overloading, we need to master the use of
friend
functions.
A
friend
function gives a
nonmember function in C++[1] access to the hidden members of the class and must be declared inside the class declaration to which it is a friend.
The function is prefaced by the keyword
friend
and can appear in any part of the class without affecting its meaning.
Our style in this course is to place the
friend
declaration in the
public
part of the class. Since access has no effect on the
friend
declaration,
friend
functions are conceptually public.
Member functions of one class can be
friend
functions of another class. In this case, they are declared in the class to which they are a friend, using the scope resolution operator to qualify its function name. If all member functions of one class are
friend
functions of a second class, this can be specified by using the general form:
friend class
class name.
The following declarations illustrate this syntax:
class window {
.....
friend void refresh(window w); //friend
friend void terminal::draw(window w); //friend
};
class node {
.....
friend class tree;
//tree members have access to node
};
When should I declare a friend function in C++?
In C++, a friend function is a function that is not a member of a class but has access to the private and protected members of the class. Declaring a friend function should be done carefully and only under specific conditions, as it breaks encapsulation and can lead to less maintainable code. Here are the conditions under which you should consider declaring a friend function:
- When You Need Access to Private or Protected Members
- If a function outside a class needs to access the private or protected members of the class, and making those members public is not desirable, you can declare the function as a friend.
- Example: Overloading operators (e.g., `<<` or `>>`) for custom classes often requires access to private data members.
class MyClass {
private:
int data;
public:
friend void printData(const MyClass& obj); // Friend function declaration
};
void printData(const MyClass& obj) {
std::cout << obj.data; // Accessing private member
}
- Operator Overloading for Non-Member Functions
- When overloading operators (e.g., `+`, `-`, `<<`, `>>`) that involve objects of two different classes or require symmetric behavior, you often need to declare the operator function as a friend.
- Example: Overloading the `<<` operator for custom output.
class MyClass {
private:
int data;
public:
MyClass(int d) : data(d) {}
friend std::ostream& operator<<(std::ostream& os, const MyClass& obj);
};
std::ostream& operator<<(std::ostream& os, const MyClass& obj) {
os << obj.data; // Accessing private member
return os;
}
- Utility Functions That Operate on Multiple Classes
- If a function needs to operate on private or protected members of multiple classes, it can be declared as a friend of all those classes.
- Example: A function that compares private data members of two different classes.
class ClassA {
private:
int dataA;
friend int compare(const ClassA& a, const ClassB& b);
};
class ClassB {
private:
int dataB;
friend int compare(const ClassA& a, const ClassB& b);
};
int compare(const ClassA& a, const ClassB& b) {
return a.dataA - b.dataB; // Accessing private members of both classes
}
- When Encapsulation is Less Important Than Functionality
- In some cases, the need for specific functionality outweighs the importance of encapsulation. For example, in tightly coupled systems or when working with legacy code, friend functions can be used to simplify interactions between classes.
- Testing and Debugging
- During development, you might declare a function as a friend to allow unit tests or debugging tools to access private members without exposing them in the public interface. However, this should be temporary and removed in production code.
Key Considerations
- Encapsulation: Friend functions break encapsulation, so use them sparingly and only when absolutely necessary.
- Alternatives: Consider whether the same functionality can be achieved using public member functions or getter/setter methods before resorting to friend functions.
- Maintainability: Overuse of friend functions can make code harder to maintain and understand, as it increases coupling between classes and external functions.
Example of When Not to Use Friend Functions
If you can achieve the same functionality using public member functions or other design patterns (e.g., composition or inheritance), avoid using friend functions. For example, instead of making a function a friend to access private data, consider providing a public method to retrieve the data.
class MyClass {
private:
int data;
public:
int getData() const { return data; } // Better than using a friend function
};
In summary, declare a friend function in C++ when you need to grant external functions access to private or protected members, and when no better alternative exists. Always weigh the trade-offs between functionality and encapsulation.
Objects, Abstraction, Data Structures
Other classes or nonmember functions are friends
C++ allows classes to declare that other classes or nonmember functions are friends, and can access 1) protected and 2) private data members and methods. For example, the SpreadsheetCell class could specify that the Spreadsheet class is its “friend” like this:
class SpreadsheetCell
{
public:
friend class Spreadsheet;
// Remainder of the class omitted for brevity
};
Now all the methods of the Spreadsheet class can access the private and protected data and members of the SpreadsheetCell class.
Similarly, you can specify that one or more functions or members of another class are friends.
For example, you might want to write a function to verify that the value and the string of a SpreadsheetCell object are really in synch. You might want this verification routine to be outside the SpreadsheetCell class to model an external audit, but the function should be able to access the internal data members of the object in order to check it properly. Here is the SpreadsheetCell class definition with a friend
checkSpreadsheetCell()
function:
class SpreadsheetCell{
public:
// Omitted for brevity
friend bool checkSpreadsheetCell(const SpreadsheetCell &cell);
// Omitted for brevity
};
The friend declaration in the class serves as the function's prototype. There is no need to write the prototype elsewhere (although it is harmless to do so).Here is the function definition:
bool checkSpreadsheetCell(const SpreadsheetCell &cell)
{
return (SpreadsheetCell::stringToDouble(cell.mString) == cell.mValue);
}
You write this function just like any other function, except that you can directly access private and protected data members of the SpreadsheetCell class. You do not repeat the friend keyword on the function definition.
friend 1) classes and 2) methods are easy to abuse, since they allow you to violate the
principle of abstraction by exposing internals of your class to other classes or functions. Thus, you should use them only in limited circumstances such as operator overloading.
Let's dive deeper into the meaning of friend, drawing a parallel between human-LLM interaction as a "friendship" and the "friend function" in C++ that grants access to private members. Just like how a
friend function gets special access to a class’s private and protected members without being a true member, your interaction with a LLM gives you access to knowledge without being a "true" human companion.
In both cases, "friendship" grants 'privileged access' while maintaining an external boundary.
Friend Function - Quiz
[1]nonmember function in C++: In C++, a non-member function is a function that exists outside of any class definition. These functions operate independently of any specific object and are accessed directly by their name, without the need for a class instance or the dot operator.

