Note

This section uses overrider containers, described in the Headers section.

friend is a controversial feature. OpenMethod aims to interact well with all of C++, as much as feasible for a library, and leaves the choice of using friend, or not, to the user.

Let’s consider yet another variation of the pay example. This time, we want to update a balance variable in a Payroll class, when an employee is paid. Thus we pass the payroll object to the pay method:

BOOST_OPENMETHOD(
    pay, (Payroll & payroll, boost::openmethod::virtual_ptr<const Employee>),
    double);

BOOST_OPENMETHOD declares an overrider container for pay in the current namespace, even though it does not define any overrider by itself. We can thus name the individual address containers in friend declarations. But note that at this point, the containers have not been specialized yet! In particular, the fn member function does not exist yet. Instead, we declare friendship to the container itself:

class Payroll {
  public:
    double balance() const {
        return balance_;
    }

  private:
    double balance_ = 1'000'000.0;

    void update_balance(double amount) {
        // throw if balance would become negative
        balance_ += amount;
    }

    friend BOOST_OPENMETHOD_OVERRIDER(
        pay, (Payroll & payroll, boost::openmethod::virtual_ptr<const Employee>),
        double);
    friend BOOST_OPENMETHOD_OVERRIDER(
        pay,
        (Payroll & payroll, boost::openmethod::virtual_ptr<const Salesman>),
        double);
};

We can now implement the pay overriders:

BOOST_OPENMETHOD_OVERRIDE(
    pay, (Payroll & payroll, boost::openmethod::virtual_ptr<const Employee>),
    double) {
    double pay = 5000.0;
    payroll.update_balance(-pay);

    return pay;
}

BOOST_OPENMETHOD_OVERRIDE(
    pay,
    (Payroll & payroll, boost::openmethod::virtual_ptr<const Salesman> emp),
    double) {
    double base = next(payroll, emp);
    double commission = emp->sales * 0.05;
    payroll.update_balance(-commission);

    return base + commission;
}

// ...and let's not forget to register the classes
BOOST_OPENMETHOD_CLASSES(Employee, Salesman)

We can also declare friendship en masse:

class Payroll {
  public:
    double balance() const {
        return balance_;
    }

  private:
    double balance_ = 1'000'000.0;

    void update_balance(double amount) {
        // throw if balance would become negative
        balance_ += amount;
    }

    template<typename...>
    friend struct BOOST_OPENMETHOD_OVERRIDERS(pay);
};

Note, however, that this makes all the overriders of any pay method, with any signature, in the current namespace, friends of Payroll. Unfortunately, C++ does not currently allow partial specialization of friend declarations.