Beginner's Guide
    First Steps
    Input & Output
    Custom Types – Part 1
    Diagnostics
    Standard Library
    Code Organization
    Custom Types – Part 2
    Generic Programming
    Memory Management
    Software Design Basics

    FriendsFriendsfriend

    class MyType { friend class Other; };

    grants type Other access to private members of MyType


    class MyType { friend void print(MyType const&); };

    grants free-standing function print access to private members of MyType


    • public members / member functions can be accessed by all functions or types
    • private data can only be accessed by member functions of the same type
    • friend allows a limited number of functions/types access to private members
    • split an abstraction into several friend types with (mutual) private access
    • keep members hidden from any other type/function except for a select few friends
    • write free-standing friend functions that can act like member functions
    • prevent implicit argument conversions

    friend Types Types

    Example: Split Data + View Example: Data + View Data+View

    • access current state of a simulation from different threads, network processes, …
    • at any given time only a subset of results is valid and should be readable from a simulation
    • handle situations when simulation no longer exists but other processes still want to access it
    • need a way to regulate/restrict (concurrent) access to simulation objects
    • simulation data should be private to (almost) all other functions & types
    class Simulation {
      // grant views access to private data:
      friend class SimulationView;
      // hidden state …
    public:
      // only ctor & dtor are public 
      Simulation(Settings const&);  // init & run
      ~Simulation();                // finalize
    };
    
    class SimulationView { public: // connect to simulation object explicit SimulationView(Simulation const*); // functions for observing simulation go here };
    • multiple, independent views per simulation
    • views can control and possibly defer access to a simulation
    • views can also handle requests even if simulation object no longer exists
    • view objects are the only way to access simulation data
    • internal state of Simulation can be kept hidden from all other types

    friend Functions Functions

    Example: Stream Input of Private Data Example: Stream Input Stream Input

    class Point2d {
      double x_;  // private!
      double y_;
    public:
      explicit   Point2d(double x, double y): x_{x}, y_{y} {}
      double x() const { return x_; }
      double y() const { return y_; }
      // can access private members of Point2d:
      friend std::istream& operator >>   (std::istream& is, Point2d& p) {
        return is >> p.x_ >> p.y_;
      }
    };
    
    int main() { Point2d p {0,0}; std::cin >> p; // }
    • is a free-standing (operator) function and not a member function
    • is declared and defined in the scope of class Point2d
    • has access to all private members of Point2d

    Functions taking an argument of type T are effectively part of T's interface, just like regular member functions.

    Preventing Implicit Conversions No Implicit Conversions No Conversions

    Friend functions like foo that are declared in the scope of a class A can only be found, if one of the arguments in the call expression actually is an object of type A:

    class B { };
    
    class A { public:
      A() {}
      A(B) {}    // implicit
      A(int) {}  // implicit
      friend void foo(A)   { } 
      friend void foo(B)   { } 
      friend void foo(int) { } 
    };
    
    void bar(A) { }
    A a1{ };      // 
    A a2{ B{} };  // 
    A a3{ 47 };   // 
    
    bar( A{} ); // // implicit conversions: bar( B{} ); // bar( A{B{}} ) bar( 123 ); // bar( A{123} )
    // friend 'foo': foo( A{} ); // // can't find foo(B) & foo(int), // no implicit conversions to 'A' foo( B{} ); // foo( 123 ); //
    class unit_ratio { public:
      constexpr explicit 
      unit_ratio(int denominator);
      // NO inverted(unit_ratio) on purpose!
      
    };
    class ratio { 
      
    public:
      explicit
      ratio(int numerator,         int denominator=1);
      // implicit conversion from unit_ratio:
      ratio(unit_ratio r);
      
      friend ratio inverted(ratio a)     {  }
    };
    int main() {
      ratio x {3,7};
      ratio y = inverted(x);  // y: 7/3
      // no accidental implicit conversions:
      unit_ratio fifth {5};
      // does not compile:
      auto five = inverted(fifth);  // good!
    }

    Because ratio objects can be implicitly constructed from unit_ratio objects, any free-standing non-friend function taking ratio as input (by value or non-const reference) could also be called with unit_ratio objects.

    If inverted(ratio) had been declared in global scope (instead of as friend inside of ratio), we could have used it to call inverted with unit_ratio objects despite the fact that we explicitly did not want that!

    In general, implicit conversions (like the one from unit_ratio to ratio) are not a good idea. They can create accidental bugs and unnecessary runtime/memory overhead.