tucuxi.org

Friends in C++

The friend keyword in C++ is often misunderstood. There's a few good reasons to make use of friend in your C++ code, but first let's go into what it means to be a friend, and why C++ needs friends at all.

C++ classes have three levels of access to members; public, protected, and private. Marking a function or class as a friend allows them to access private and protected members of another class.

For example, the following code would not compile, as balance is a private member of BankAccount:

class BankAccount {
 public:
  bool withdraw(float amount);

 private:
  float balance;
};

void remove_money(BankAccount &account) {
  account.balance -= 100.0f;
}

So, how can you give remove_money() access to balance? You add remove_money as a friend. Similarly, you can also give another class the same level of access.

class BankAccount {
 public:
  friend void remove_money(BankAccount &account);
  friend class BankAccountUnitTest;
...

Why be a friend?

There's a few common reasons that you might want to use friendship to provide access into your classes.

Friendship isn't perfect.

Like many of C++'s other features, the use of the friend keyword is somewhat contentious across the developer community. Some engineers would instead prefer to provide explicit accessors and mutators, or even using a derived class instead. Consider the style of the existing codebase that you are working with before widely embarking on the use of friend; while there are situations where you may need to use friend, you should strive to fit in with existing style.

Friendship isn't inheritable.

Another thing that may not be immediately obvious is that being a friend is not an attribute that derived classes inherit. Consider, for example, the following code hierarchy:

class DataType {
 private:
  int value;

 public:
  friend class MultiplyByTwo;
};

class MultiplyByTwo {
 public:
  virtual void multiply(DataType &dt) {
    dt.value *= 2;
  }
};

class MultiplyByThree : public MultiplyByTwo {
 public:
  virtual void multiply(DataType &dt) {
    dt.value *= 3;
  }
};

Note that MultiplyByThree will not successfully compile; the friendship granted to MultiplyByTwo does not apply to all child classes of MultiplyByTwo;

Friendship isn't reciprocal.

Just because I consider you a friend, it doesn't mean that you'll do the same in return. Likewise, C++'s friend keyword is uni-directional; if class A declares friend class B, that doesn't mean class A will have access to class B's private members.