Recent from talks
Nothing was collected or created yet.
Friend class
View on WikipediaA friend class in C++ can access the private and protected members of the class in which it is declared as a friend.[1] A significant use of a friend class is for a part of a data structure, represented by a class, to provide access to the main class representing that data structure. The friend class mechanism allows to extend the storage and access to the parts, while retaining proper encapsulation as seen by the users of the data structure.
Similar to a friend class, a friend function is a function that is given access to the private and protected members of the class in which it is declared as a friend.
Since C++26, C++ supports "variadic friends" (i.e. friend classes that come from variadic templates).[2]
Example
[edit]The following example demonstrates the use of a friend-class for a graph data structure, where the graph is represented by the main class Graph, and the graph's vertices are represented by the class Vertex.
import std;
template <typename T>
using SharedPtr = std::shared_ptr<T>;
using String = std::string;
template <typename T>
using UniquePtr = std::unique_ptr<T>;
template <typename T>
using HashSet = std::unordered_set<T>; // default-specialize the remaining template-parameters
class Vertex {
private:
// Vertex gives access-rights to Graph.
friend class Graph;
HashSet<SharedPtr<Vertex>> edges;
String name;
using EdgesIterator = decltype(edges.cbegin());
public:
explicit Vertex(const String& name):
name{std::move(name)} {}
EdgesIterator begin() const {
return edges.cbegin();
}
EdgesIterator end() const {
return edges.cend();
}
String getName() const {
return name;
}
};
class Graph {
private:
HashSet<SharedPtr<Vertex>> vertices;
using VerticesIterator = decltype(vertices.cbegin());
public:
~Graph() {
while (!vertices.empty()) {
VerticesIterator vertex = vertices.begin();
removeVertex(*vertex);
}
}
void addVertex(const String& name) {
UniquePtr<Vertex> vertex = std::make_unique<Vertex>(name);
VerticesIterator iter = vertices.insert(vertex.get());
}
void removeVertex(SharedPtr<Vertex> vertex) {
vertices.erase(vertex);
}
void addEdge(SharedPtr<Vertex> from, SharedPtr<Vertex> to) {
// Graph can access Vertex's private fields because Vertex declared Graph as
// a friend.
from->edges.insert(to);
}
VerticesIterator begin() const {
return vertices.cbegin();
}
VerticesIterator end() const {
return vertices.cend();
}
};
Using variadic friends:
import std;
template <typename... Friends>
class ClassWithFriends {
private:
int secretValue;
friend Friends...;
public:
explicit ClassWithFriends(int secret):
secretValue{secret} {}
};
class A {
public:
void readSecret(const class ClassWithFriends<A, B>& instance) const {
std::println("Inspecting secret value from A: {}", instance.secretValue);
}
};
class B {
public:
void readSecret(const class ClassWithFriends<A, B>& instance) const {
std::println("Inspecting secret value from B: {}", instance.secretValue);
}
};
int main(int argc, char* argv[]) {
ClassWithFriends<A, B> secretHolder(135);
A a;
B b;
a.readSecret(secretHolder);
b.readSecret(secretHolder);
}
Encapsulation
[edit]A proper use of friend classes increases encapsulation, because it allows to extend the private access of a data-structure to its parts --- which the data-structure owns --- without allowing private access to any other external class. This way the data-structure stays protected against accidental attempts at breaking the invariants of the data-structure from outside.
It is important to notice that a class cannot give itself access to another class's private part; that would break encapsulation. Rather, a class gives access to its own private parts to another class --- by declaring that class as a friend. In the graph example, Graph cannot declare itself a friend of Vertex. Rather, Vertex declares Graph a friend, and so provides Graph an access to its private fields.
The fact that a class chooses its own friends means that friendship is not symmetric in general. In the graph example, Vertex cannot access private fields of Graph, although Graph can access private fields of Vertex.
Alternatives
[edit]A similar, but not equivalent, language feature is given by C#'s internal access modifier keyword, which allows classes inside the same assembly to access the private parts of other classes. This corresponds to marking each class a friend of another in the same assembly; friend classes are more fine-grained.
Programming languages which lack support for friend classes, or a similar language feature, will have to implement workarounds to achieve a safe part-based interface to a data-structure. Examples of such workarounds are:
- Make the parts' fields public. This solution decreases encapsulation by making it possible to violate invariants of the data-structure from outside.
- Move all mutable structural data away from the part to the data-structure, and introduce indirection back from each part to its data-structure. This solution changes the organization of the data structure, and increases memory consumption in cases where there would otherwise be no need for this information.
Properties
[edit]- Friendships are not symmetric – if class
Ais a friend of classB, classBis not automatically a friend of classA. - Friendships are not transitive – if class
Ais a friend of classB, and classBis a friend of classC, classAis not automatically a friend of classC. - Friendships are not inherited – if class
Baseis a friend of classX, subclassDerivedis not automatically a friend of classX; and if classXis a friend of classBase, classXis not automatically a friend of subclassDerived. However, if classYis a friend of subclassDerived, classYwill also have access to protected portions of classBase, just as subclassDeriveddoes.
References
[edit]- ^ "9 More on C++".
- ^ Jody Hagins, Arthur O'Dwyer (22 March 2024). "P2893R3 - Variadic friends". open-std.org. ISO/IEC 14882 Programming Languages — C++, ISO/IEC JTC1/SC22/WG21.
External links
[edit]Friend class
View on Grokipediafriend keyword followed by the class name, as in friend class OtherClass;.[3] This syntax does not require the friend class to be fully defined at the point of declaration, though it must be known by the time its members access the granted class's internals.[1] Once declared, all member functions of the friend class—including both instance and static methods—gain unrestricted access to the private and protected elements of the host class, treating them as if they were public.
Friendship in C++ is a deliberate design choice to balance information hiding with necessary interoperability, but it comes with strict rules to prevent unintended exposure.[2] Notably, friendship is neither inherited nor transitive: if Class A is a friend of Class B, then derived classes from A do not automatically become friends of B, and friends of A are not friends of B.[1] It is also not symmetric, meaning that declaring A as a friend of B does not make B a friend of A unless explicitly stated.[3] These properties ensure that access remains controlled and explicit, promoting maintainable code while avoiding the pitfalls of overly permissive interfaces.
In practice, friend classes are used sparingly to maintain strong encapsulation, often in scenarios like implementing binary operators (e.g., operator<< for streams) or managing complex data structures where one class needs deep integration with another.[2] Overuse can lead to fragile dependencies, so modern C++ guidelines recommend preferring public interfaces, getters/setters, or templates where possible to minimize reliance on friends.[3] Since C++11, enhancements to friend declarations allow more flexible type specifiers, such as using typename for dependent types in templates, further refining its utility in generic programming.[1]
Definition and Purpose
Definition
In C++, a friend class is a mechanism that permits a designated class to access the private and protected members of another class, thereby overriding the standard access restrictions imposed by the object's encapsulation model. This access grant is explicit and one-way, meaning the befriended class can interact with the internal details of the host class as if they were its own members, without requiring public exposure of those elements.[3] A key distinction exists between friend classes and friend functions: while a friend function provides targeted access to private and protected members for a specific non-member function, a friend class extends this privilege to all member functions of the friend class, enabling comprehensive interaction with the host class's internals. This broader scope makes friend classes suitable for scenarios where an entire collaborating class needs unfettered access, rather than isolated operations.[3] The concept of friend classes was introduced by Bjarne Stroustrup during the development of "C with Classes" from 1979 to 1983, as part of the initial protection model to enable flexible access control without compromising the overall design of object-oriented features.[4] Initially, only friend classes were supported, granting access to all member functions of the befriended class; this was later expanded to include individual friend functions.[4] The design drew inspiration from operating system access rights, aiming to balance security with practical utility in large-scale programming.[4] Friend classes operate against the backdrop of C++'s fundamental access specifiers—private and protected—which restrict member visibility to within the class or its derived classes, respectively, to enforce data hiding and modularity. By declaring a friend relationship, these baseline controls are selectively bypassed, allowing controlled exceptions to the encapsulation principle without altering the specifiers themselves.[3]Purpose
The friend class mechanism in C++ primarily enables controlled access to private and protected members of a class by another class, facilitating scenarios where tight integration is necessary without broadly compromising encapsulation. One key purpose is to support operator overloading, particularly for non-member operators like stream insertion (operator<<), which require access to internal data to serialize objects without exposing it publicly. This approach allows classes to integrate seamlessly with standard I/O streams, for example, by declaring a non-member operator<< function as a friend to allow access to private members for output to streams like std::ostream.[1][3]
Another motivation is to permit tightly coupled classes, such as iterators accessing the internals of container classes, ensuring efficient traversal without public interfaces that could invite misuse. In custom container designs, the iterator class is often declared as a friend of the container to manipulate private data structures directly, mirroring practices in the C++ standard library where iterators interact deeply with container implementations. Additionally, friend classes support unit testing by granting test classes access to private members, allowing verification of internal behavior without adding public getters or setters that might alter the class's external contract.[5][6]
These uses maintain encapsulation for unrelated external code by limiting access to designated friends, thereby avoiding the need for excessive public accessor methods that could increase coupling and maintenance overhead. In design patterns like the visitor pattern, friend declarations enable external operations to traverse and modify object hierarchies without relying on inheritance or public exposure. However, this feature is motivated by its selectivity; it is not intended for loose coupling, as friending creates explicit dependencies that can undermine information hiding principles central to object-oriented design.[3][7][8]
Syntax and Declaration
Friend Class Declaration
In C++, a friend class declaration specifies that an entire class is granted access to the private and protected members of another class, allowing the friend class to interact closely with the befriended class's internals. The syntax for declaring a class as a friend uses thefriend keyword followed by class and the name of the friend class, typically written as friend class ClassName; within the body of the befriended class's definition.[1] This declaration can employ an elaborated-type-specifier (e.g., friend class ClassName;), which is valid until C++26, or a simple-type-specifier (e.g., friend ClassName;) introduced in C++11, though the latter requires the class to be previously declared to avoid errors.[1]
The placement of the friend class declaration occurs inside the befriended class's definition, where it can appear in the public, private, or protected sections; access specifiers have no effect on the meaning of friend declarations.[1] If the friend class has not been defined or forward-declared prior to the friend declaration, the elaborated-type-specifier form implicitly provides a forward declaration for the friend class, enabling its use without a separate prior declaration in the same scope.[1] In contrast, the simple-type-specifier form does not introduce a forward declaration and will be ignored by the compiler if the named type is not recognized as a class at that point, potentially leading to compilation failure if access is attempted later.[1] For mutual friendship between two classes, each must explicitly declare the other as a friend using forward declarations to resolve circular dependencies, such as forward-declaring both classes before their definitions and including reciprocal friend class statements in each.[9][10]
The scope of a friend class declaration encompasses the entire friend class, granting it unrestricted access to all private and protected non-static and static members of the befriended class, including data members, member functions, and nested types, without needing inheritance or other mechanisms.[1][11] This access applies to instances of the friend class operating on instances of the befriended class, and it is not inherited by derived classes of the friend nor transitive to other friends.[1]
Friend class declarations are resolved entirely at compile-time, introducing no runtime overhead as the access permissions are enforced statically by the compiler during type checking and code generation.[1] If the friend class name is ambiguous—such as due to namespace conflicts, multiple declarations, or injected class names—the compiler will issue an error, preventing compilation until the ambiguity is resolved through qualification or scoping adjustments.[12]
Friend Function Declaration
A friend function declaration in C++ is specified within the body of a class definition using thefriend keyword followed by a function declaration, which grants that non-member function access to the private and protected members of the enclosing class as if it were a member function.[13] The basic syntax is friend ReturnType functionName(Parameters);, where the declaration must appear inside the class but the function body is typically defined outside the class unless it is an inline definition.[13]
Variations of friend function declarations include support for overloaded functions, where multiple declarations with the same name but different parameters can each be granted friendship independently; member functions of another class, declared as friend OtherClass::MemberFunction(Parameters);; and global functions, which are commonly used for operator overloading to enable non-member access to private data.[13] These declarations allow precise control over which specific functions receive elevated access privileges.
Key rules governing friend function declarations stipulate that the function must be defined outside the class unless provided as an inline friend definition, and no storage class specifiers (such as static or extern) are permitted in the declaration.[13] Access is granted exclusively to the exact function signature declared as a friend, meaning changes to parameters or return type would require a separate friendship declaration.[13]
When a class is defined within a namespace, a friend function declaration integrates by placing the friend's name in the innermost enclosing namespace scope, though it is not visible outside the class unless explicitly redeclared at the namespace level.[13] This ensures namespace isolation while allowing the friend to operate within the appropriate scope for accessing class members.
Examples
Basic Example
A basic example of a friend class in C++ involves aBox class that stores private dimensions and declares another class, Printer, as a friend to access those dimensions directly for computation and output.
Consider the following code snippet, which demonstrates the declaration and usage of a friend class:
#include <iostream>
class [Box](/page/Box) {
private:
double width;
double height;
public:
[Box](/page/Box)(double w, double h) : width(w), height(h) {}
// Declare [Printer](/page/Declare) as a friend class
friend class Printer;
};
class Printer {
public:
void printArea(const [Box](/page/Box)& box) {
// Friend class accesses private members directly
double area = box.width * box.height;
std::cout << "Area: " << area << std::endl;
}
};
int main() {
Box myBox(4.0, 5.0);
Printer printer;
printer.printArea(myBox); // Outputs: Area: 20
return 0;
}
#include <iostream>
class [Box](/page/Box) {
private:
double width;
double height;
public:
[Box](/page/Box)(double w, double h) : width(w), height(h) {}
// Declare [Printer](/page/Declare) as a friend class
friend class Printer;
};
class Printer {
public:
void printArea(const [Box](/page/Box)& box) {
// Friend class accesses private members directly
double area = box.width * box.height;
std::cout << "Area: " << area << std::endl;
}
};
int main() {
Box myBox(4.0, 5.0);
Printer printer;
printer.printArea(myBox); // Outputs: Area: 20
return 0;
}
Box class declaration, where width and height are private members initialized via a public constructor. The friend declaration friend class Printer; inside Box grants the Printer class unrestricted access to Box's private members, as defined in the C++ language specification.[1]
Next, the Printer class is defined with a public member function printArea that takes a Box object by const reference. Within this function, Printer directly accesses box.width and box.height to compute the area, bypassing the need for public getter methods in Box. In the main function, a Box object is instantiated with dimensions 4.0 and 5.0, a Printer object is created, and printArea is invoked on the Box instance.[1]
When compiled and executed (e.g., using a C++11 or later compliant compiler like g++ with command g++ -std=c++11 example.cpp -o example && ./example), the program outputs "Area: 20" without compilation errors related to access violations. This confirms the friend relationship enables Printer to treat Box's private members as if they were public, while maintaining encapsulation for non-friend code.[14]
Operator Overloading Example
One common application of friend functions in C++ is overloading binary operators like addition (+) for user-defined types, such as complex numbers, where direct access to private members is required for efficient implementation.[1] Consider a Complex class that encapsulates real and imaginary parts as private double members to maintain encapsulation. The class declares a global operator+ as a friend function, granting it permission to read and manipulate these private fields without public getter methods.[15]
Here is a representative implementation:
#include <iostream>
class Complex {
private:
double real;
double imag;
public:
Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}
// Declare friend function for operator+
friend Complex operator+(const Complex& a, const Complex& b);
// Helper function to output the complex number
void print() const {
std::cout << "(" << real << " + " << imag << "i)" << std::endl;
}
};
// Definition of the friend operator+ function
Complex operator+(const Complex& a, const Complex& b) {
return Complex(a.real + b.real, a.imag + b.imag);
}
#include <iostream>
class Complex {
private:
double real;
double imag;
public:
Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}
// Declare friend function for operator+
friend Complex operator+(const Complex& a, const Complex& b);
// Helper function to output the complex number
void print() const {
std::cout << "(" << real << " + " << imag << "i)" << std::endl;
}
};
// Definition of the friend operator+ function
Complex operator+(const Complex& a, const Complex& b) {
return Complex(a.real + b.real, a.imag + b.imag);
}
Complex class allows the non-member operator+ to access a.real, a.imag, b.real, and b.imag directly, enabling the addition of corresponding components to produce a new Complex object.[1][15] The function takes two const references to avoid unnecessary copies, promoting efficiency.
To use this overloaded operator, objects can be combined using natural infix notation, such as Complex c3 = c1 + c2;, where c1 and c2 are instances of Complex. For example, if c1 is initialized as Complex(3.0, 4.0) and c2 as Complex(1.0, 2.0), then c3 evaluates to Complex(4.0, 6.0), representing the sum (3 + 4i) + (1 + 2i) = (4 + 6i). Invoking c3.print() would output: (4 + 6i). This computation occurs seamlessly through the friend function's access to private data.[15]
The use of a friend function here ensures symmetry in operator overloading: unlike a member function version (e.g., Complex operator+(const Complex& other)), which treats the left operand as this and requires the right operand to be of the same type, the non-member friend allows the left operand to be a built-in type or another class, facilitating expressions like c3 = 2.0 + c2. This design preserves encapsulation for the class while enabling expressive, intuitive syntax for arithmetic operations on complex numbers.[15]
Design Implications
Encapsulation Effects
Encapsulation in object-oriented programming, particularly in C++, refers to the bundling of data and methods within a class while restricting direct access to the internal implementation details through access specifiers such as private and protected. This mechanism enforces abstraction by preventing unauthorized access to an object's volatile parts, allowing external code to interact only with stable interfaces.[16][17] Friend declarations in C++ introduce a selective breach in this encapsulation barrier by granting specific external functions or classes access to private and protected members of the friending class. This controlled access is intended for trusted entities that require it for legitimate operations, such as operator overloading or closely coupled components in a library, but it inherently increases coupling between the involved classes, as modifications to private members may necessitate changes in friend code.[18] If friend relationships proliferate across multiple classes, they can create implicit dependencies that complicate maintenance and refactoring efforts.[18] On the positive side, friends enable necessary internal access without exposing members publicly or relying on inheritance, thereby supporting modular designs where encapsulation is preserved for untrusted code while allowing efficient interactions in trusted contexts, such as within software frameworks.[2] However, this approach deviates from the strict "black box" ideal of encapsulation, where a class's internals remain completely hidden from all external entities, potentially making the system's dependencies less transparent and more prone to unintended interactions.[18] Overuse of friends can exacerbate these issues by fostering tightly coupled designs that hinder long-term maintainability.[19]Key Properties
Friend declarations in C++ grant a function or another class the same level of access to the private and protected members of the enclosing class as its own member functions would have. However, since friend functions are non-member functions, they do not receive an implicit this pointer to the object whose members they access, requiring explicit object parameters for such operations.[13] Friendship is not symmetric, meaning that if class A declares class B as a friend, class B does not automatically have access to A's private members unless A is similarly declared a friend within B. Furthermore, friendship is neither transitive nor inherited; a friend of a friend is not automatically a friend, and derived classes of a friend class do not inherit that friendship status.[13] In the context of templates, declaring a class template as a friend of an enclosing class makes every specialization of that template—whether implicitly instantiated, explicitly specialized, or partially specialized—a friend, provided the declaration uses the template name without arguments. Declaring specific instantiations, such asfriend class MyTemplate<int>, requires explicit naming, while partial specializations cannot be directly specified in friend declarations and may lead to compilation errors if attempted. For function templates as friends, the declaration grants friendship to all specializations that match the declared signature, necessitating precise specification to avoid unintended access grants.[13]
A friend declaration places the name of the friended entity into the innermost enclosing namespace of the class but does not make it visible for name lookup from outside the class body unless the entity is separately declared in that scope. Consequently, friend declarations do not imply the prior existence of the friended function or class and have no impact on external name resolution.[13]
The friend feature is a core part of the C++ standard, introduced in C++98 and retained through C++26, ensuring portability across all standards-compliant compilers without variations in core behavior.[13]
Alternatives and Comparisons
Within C++
In C++, several mechanisms provide controlled access to class members without relying on friend declarations, thereby maintaining encapsulation through different structural approaches. These alternatives are particularly useful when the relationship between classes does not necessitate the explicit access privileges granted by friends, allowing for more modular and extensible designs. Getters and setters, implemented as public member functions, offer a common way to achieve read and write access to private data members while preserving encapsulation. A getter function returns the value of a private member, and a setter modifies it, often with validation logic to enforce invariants. This approach adds some boilerplate code but ensures that internal representation remains hidden from clients, promoting information hiding as a core principle of object-oriented design. For instance, in a class representing a point, agetX() method could expose the x-coordinate without revealing how it is stored.
Inheritance provides another alternative by allowing derived classes to access protected members of a base class, which are inaccessible to unrelated classes. This is suitable for "is-a" relationships where extension or specialization is intended, such as a DerivedShape class accessing protected drawing logic in a BaseShape. However, it is not applicable for arbitrary collaborations outside hierarchical structures, as it imposes inheritance-specific constraints like the Liskov substitution principle. Protected access thus supports polymorphism without the tight coupling of friends.
Composition, particularly through nested classes, enables tighter integration by embedding one class within another. A nested class, declared inside an enclosing class, has the same access rights as any member of the enclosing class, including to its private and protected members. This allows the nested class to manipulate the outer class's internals directly, facilitating implementation details like iterators or helper structures without exposing them publicly. For example, a container class might define a private nested iterator class that accesses its private storage. While this promotes locality, the nested class must still respect the enclosing class's access specifiers for its own members.[20]
Making members public offers direct access but undermines encapsulation by exposing implementation details, making it rarely recommended except for simple data structures like POD types. In contrast, friends are preferable for non-hierarchical or symmetric couplings, such as between peer classes in a graph algorithm, where inheritance would be inappropriate and getters might introduce excessive indirection. These alternatives thus trade off flexibility against the risks of unintended access, with friends reserved for cases where no cleaner structural fit exists.
