There’s infinite ways to organize code. In C# or Rust where this isn’t an option, you might use nested classes or traits hidden behind a module/namespace.
Good use cases are data structures with associated helper classes. For example, a collection/tree and an iterator/tree-walker for working with elements of the collection. Or for something like a smart memory allocator (an arena or slab allocator), you might use a friend-class to wrap elements returned from the allocator, representing their connection back to it (for freeing up when done or to manage the allocation structure in ie a heap or sorted tree).
There’s infinite ways to organize code. In C# or Rust where this isn’t an option, you might use nested classes or traits hidden behind a module/namespace.
Good use cases are data structures with associated helper classes. For example, a collection/tree and an iterator/tree-walker for working with elements of the collection. Or for something like a smart memory allocator (an arena or slab allocator), you might use a friend-class to wrap elements returned from the allocator, representing their connection back to it (for freeing up when done or to manage the allocation structure in ie a heap or sorted tree).