Friend Functions & Classes
Part of the Object Oriented Programming section of Coddy's C++ journey — lesson 32 of 104.
Sometimes a function or class outside your class needs access to its private members. Rather than making those members public, C++ provides the friend keyword to grant selective access while maintaining encapsulation.
A friend function is declared inside a class but is not a member of that class. It can access the class's private and protected members:
class Box {
double width;
public:
Box(double w) : width(w) {}
// Declare printWidth as a friend
friend void printWidth(const Box& b);
};
// Friend function definition - NOT a member function
void printWidth(const Box& b) {
std::cout << b.width; // Can access private member
}Notice that printWidth is defined outside the class without the scope resolution operator. It's a regular function that happens to have special access privileges.
You can also make an entire class a friend, granting all its member functions access to private members:
class Engine {
int horsepower;
friend class Mechanic; // Mechanic can access private members
public:
Engine(int hp) : horsepower(hp) {}
};
class Mechanic {
public:
void diagnose(const Engine& e) {
std::cout << e.horsepower; // Allowed - Mechanic is a friend
}
};Friendship is not mutual - if Engine declares Mechanic as a friend, Mechanic can access Engine's private members, but not vice versa. Use friends sparingly, as they create tight coupling between classes. They're most useful for operator overloading and closely related helper functions.
Challenge
EasyLet's build a secure messaging system where a MessageReader class needs special access to read encrypted messages stored in a SecureMessage class. This is a perfect scenario for using friend functions and friend classes.
You'll create two files to organize your code:
SecureMessage.h: Define aSecureMessageclass that stores private message data and grants selective access to trusted entities. Your class should have:- Private members:
content(string) andsecretKey(int) - A constructor that takes the content and secret key
- Declare
MessageReaderas a friend class so it can access private members - Declare a friend function
decryptMessage(const SecureMessage& msg, int key)that returns the content only if the provided key matches the secret key, otherwise returns"Access Denied"
Then define the
MessageReaderclass in the same header file:- A method
readContent(const SecureMessage& msg)that directly accesses and returns the message's privatecontent - A method
verifyKey(const SecureMessage& msg, int key)that checks if the provided key matches the message'ssecretKeyand returns"Valid"or"Invalid"
Finally, define the
decryptMessagefriend function after the classes.- Private members:
main.cpp: Demonstrate both friend functions and friend classes in action. Read a message content, a secret key, and a test key from input (each on a separate line), then:- Create a
SecureMessagewith the content and secret key - Create a
MessageReaderobject - Print
"Reader access: <content>"using the reader'sreadContent()method - Print
"Key verification: <result>"usingverifyKey()with the test key - Print
"Decrypt with test key: <result>"using the friend function with the test key - Print
"Decrypt with correct key: <result>"using the friend function with the original secret key
- Create a
Remember that friend functions are defined outside the class without the scope resolution operator — they're regular functions with special access privileges. The MessageReader class, being a friend, can directly access SecureMessage's private members in all its methods.
Convert the key inputs from strings to integers using std::stoi(). Include your header file in main.cpp using #include "SecureMessage.h".
Cheat sheet
The friend keyword grants selective access to private members while maintaining encapsulation.
Friend Function: A function declared inside a class that can access its private and protected members, but is not a member of the class:
class Box {
double width;
public:
Box(double w) : width(w) {}
// Declare friend function
friend void printWidth(const Box& b);
};
// Define outside class without scope resolution operator
void printWidth(const Box& b) {
std::cout << b.width; // Can access private member
}Friend Class: An entire class can be declared as a friend, granting all its member functions access to private members:
class Engine {
int horsepower;
friend class Mechanic; // All Mechanic methods can access private members
public:
Engine(int hp) : horsepower(hp) {}
};
class Mechanic {
public:
void diagnose(const Engine& e) {
std::cout << e.horsepower; // Allowed
}
};Key Points:
- Friendship is not mutual - if A declares B as a friend, B can access A's private members, but not vice versa
- Friend functions are defined outside the class without the scope resolution operator
- Use friends sparingly as they create tight coupling between classes
- Most useful for operator overloading and closely related helper functions
Try it yourself
#include <iostream>
#include <string>
#include "SecureMessage.h"
using namespace std;
int main() {
// Read input
string messageContent;
string secretKeyStr;
string testKeyStr;
getline(cin, messageContent);
getline(cin, secretKeyStr);
getline(cin, testKeyStr);
int secretKey = stoi(secretKeyStr);
int testKey = stoi(testKeyStr);
// TODO: Create a SecureMessage with the content and secret key
// TODO: Create a MessageReader object
// TODO: Print "Reader access: <content>" using readContent()
// TODO: Print "Key verification: <result>" using verifyKey() with test key
// TODO: Print "Decrypt with test key: <result>" using decryptMessage with test key
// TODO: Print "Decrypt with correct key: <result>" using decryptMessage with secret key
return 0;
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesC++ Build & CompilationHeader Files & Source FilesNamespaces & ScopeIntroduction to OOP in C++Classes vs ObjectsThe 'this' PointerMethods (Member Functions)Attributes (Data Members)Ctors & Dtors BasicsRecap - Simple Calculator4Class Properties
Instance vs Static MembersGetters and SettersConst Member FunctionsMutable KeywordStatic Methods and VariablesFriend Functions & ClassesRecap - Bank Account Manager7Inheritance
Basic InheritanceInheritance Access LevelsCtor & Dtor Call OrderMethod OverridingVirtual Functions & VTableMultiple InheritanceVirtual InheritanceRecap - Employee Hierarchy2Memory Management
Stack vs Heap MemoryPointers and ReferencesDynamic Memory (new/delete)Smart Pointers in C++RAII in C++Recap - Dynamic Array Manager5Encapsulation
Access Specifiers in C++Access Specifiers In DepthInformation HidingStruct vs ClassNested & Inner ClassesRecap - Student Records System8Polymorphism
Compile vs Runtime PolymorphFunction OverloadingVirtual Functions RevisitedPure Virtual FunctionsAbstract ClassesInterface Design in C++Dynamic Casting & RTTIRecap - Shape Calculator3Constructors & Destructors
Default ConstructorParameterized ConstructorCopy ConstructorMove ConstructorConstructor Init ListsDelegating ConstructorsDestructor Deep DiveRule of Three / Five / ZeroRecap - String Class6Operator Overloading
Intro to Operator OverloadArithmetic Operator OverloadComparison Operator OverloadStream OperatorsAssignment Operator Overload[] and () Operator OverloadType Conversion OperatorsRecap - Matrix Class9Templates
Function TemplatesClass TemplatesTemplate SpecializationVariadic TemplatesSFINAE & Type Traits BasicsRecap - Generic Container